Merge "Fix BiDi issues in app error dialogs" into nyc-dev
diff --git a/Android.mk b/Android.mk
index 2ee7600..3ac5889 100644
--- a/Android.mk
+++ b/Android.mk
@@ -150,14 +150,14 @@
core/java/android/content/pm/IPackageStatsObserver.aidl \
core/java/android/content/pm/IOnPermissionsChangeListener.aidl \
core/java/android/database/IContentObserver.aidl \
- core/java/android/hardware/ICameraService.aidl \
- core/java/android/hardware/ICameraServiceListener.aidl \
- core/java/android/hardware/ICameraServiceProxy.aidl \
- core/java/android/hardware/ICamera.aidl \
- core/java/android/hardware/ICameraClient.aidl \
+ ../av/camera/aidl/android/hardware/ICameraService.aidl \
+ ../av/camera/aidl/android/hardware/ICameraServiceListener.aidl \
+ ../av/camera/aidl/android/hardware/ICameraServiceProxy.aidl \
+ ../av/camera/aidl/android/hardware/ICamera.aidl \
+ ../av/camera/aidl/android/hardware/ICameraClient.aidl \
+ ../av/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl \
+ ../av/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl \
core/java/android/hardware/IConsumerIrService.aidl \
- core/java/android/hardware/camera2/ICameraDeviceUser.aidl \
- core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl \
core/java/android/hardware/ISerialManager.aidl \
core/java/android/hardware/display/IDisplayManager.aidl \
core/java/android/hardware/display/IDisplayManagerCallback.aidl \
@@ -455,6 +455,10 @@
$(FRAMEWORKS_BASE_JAVA_SRC_DIRS) \
frameworks/native/aidl/binder
+LOCAL_AIDL_INCLUDES += \
+ frameworks/av/camera/aidl \
+ frameworks/native/aidl/gui
+
LOCAL_INTERMEDIATE_SOURCES := \
$(framework_res_source_path)/android/R.java \
$(framework_res_source_path)/android/Manifest.java \
@@ -577,7 +581,7 @@
frameworks/base/core/java/android/view/Display.aidl \
frameworks/base/core/java/android/view/InputDevice.aidl \
frameworks/base/core/java/android/view/InputEvent.aidl \
- frameworks/base/core/java/android/view/Surface.aidl \
+ frameworks/native/aidl/gui/android/view/Surface.aidl \
frameworks/base/core/java/android/view/WindowContentFrameStats.aidl \
frameworks/base/core/java/android/view/inputmethod/InputMethodSubtype.aidl \
frameworks/base/core/java/android/view/inputmethod/CursorAnchorInfo.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 2fe5cbe..cee8fdb 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -240,6 +240,7 @@
$(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/media/java/android/media/IRemoteControlDisplay.*)
$(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/APPS/FeatureSplit1_intermediates/src/com/android/test/split/feature/R.java)
$(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/APPS/FeatureSplit2_intermediates/src/com/android/test/split/feature/R.java)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/hardware)
# ******************************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/api/current.txt b/api/current.txt
index aeaae55..799ad0f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5258,7 +5258,7 @@
}
public static class NotificationManager.Policy implements android.os.Parcelable {
- ctor public deprecated NotificationManager.Policy(int, int, int);
+ ctor public NotificationManager.Policy(int, int, int);
ctor public NotificationManager.Policy(int, int, int, int);
method public int describeContents();
method public static java.lang.String priorityCategoriesToString(int);
@@ -5711,6 +5711,7 @@
public class WallpaperManager {
method public void clear() throws java.io.IOException;
+ method public void clear(int) throws java.io.IOException;
method public void clearWallpaperOffsets(android.os.IBinder);
method public void forgetLoadedWallpaper();
method public android.graphics.drawable.Drawable getBuiltInDrawable();
@@ -10465,7 +10466,6 @@
method public boolean hasNext();
method public java.util.Iterator<android.database.CursorJoiner.Result> iterator();
method public android.database.CursorJoiner.Result next();
- method public void remove();
}
public static final class CursorJoiner.Result extends java.lang.Enum {
@@ -19155,168 +19155,110 @@
public final class GnssClock implements android.os.Parcelable {
method public int describeContents();
- method public double getBiasInNs();
- method public double getBiasUncertaintyInNs();
- method public double getDriftInNsPerSec();
- method public double getDriftUncertaintyInNsPerSec();
- method public long getFullBiasInNs();
+ method public double getBiasNanos();
+ method public double getBiasUncertaintyNanos();
+ method public double getDriftNanosPerSecond();
+ method public double getDriftUncertaintyNanosPerSecond();
+ method public long getFullBiasNanos();
method public int getHardwareClockDiscontinuityCount();
- method public short getLeapSecond();
- method public long getTimeInNs();
- method public double getTimeUncertaintyInNs();
- method public boolean hasBiasInNs();
- method public boolean hasBiasUncertaintyInNs();
- method public boolean hasDriftInNsPerSec();
- method public boolean hasDriftUncertaintyInNsPerSec();
- method public boolean hasFullBiasInNs();
+ method public int getLeapSecond();
+ method public long getTimeNanos();
+ method public double getTimeUncertaintyNanos();
+ method public boolean hasBiasNanos();
+ method public boolean hasBiasUncertaintyNanos();
+ method public boolean hasDriftNanosPerSecond();
+ method public boolean hasDriftUncertaintyNanosPerSecond();
+ method public boolean hasFullBiasNanos();
method public boolean hasLeapSecond();
- method public boolean hasTimeUncertaintyInNs();
+ method public boolean hasTimeUncertaintyNanos();
method public void reset();
- method public void resetBiasInNs();
- method public void resetBiasUncertaintyInNs();
- method public void resetDriftInNsPerSec();
- method public void resetDriftUncertaintyInNsPerSec();
- method public void resetFullBiasInNs();
+ method public void resetBiasNanos();
+ method public void resetBiasUncertaintyNanos();
+ method public void resetDriftNanosPerSecond();
+ method public void resetDriftUncertaintyNanosPerSecond();
+ method public void resetFullBiasNanos();
method public void resetLeapSecond();
- method public void resetTimeUncertaintyInNs();
+ method public void resetTimeUncertaintyNanos();
method public void set(android.location.GnssClock);
- method public void setBiasInNs(double);
- method public void setBiasUncertaintyInNs(double);
- method public void setDriftInNsPerSec(double);
- method public void setDriftUncertaintyInNsPerSec(double);
- method public void setFullBiasInNs(long);
+ method public void setBiasNanos(double);
+ method public void setBiasUncertaintyNanos(double);
+ method public void setDriftNanosPerSecond(double);
+ method public void setDriftUncertaintyNanosPerSecond(double);
+ method public void setFullBiasNanos(long);
method public void setHardwareClockDiscontinuityCount(int);
- method public void setLeapSecond(short);
- method public void setTimeInNs(long);
- method public void setTimeUncertaintyInNs(double);
+ method public void setLeapSecond(int);
+ method public void setTimeNanos(long);
+ method public void setTimeUncertaintyNanos(double);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
}
public final class GnssMeasurement implements android.os.Parcelable {
method public int describeContents();
- method public double getAccumulatedDeltaRangeInMeters();
- method public short getAccumulatedDeltaRangeState();
- method public double getAccumulatedDeltaRangeUncertaintyInMeters();
- method public double getAzimuthInDeg();
- method public double getAzimuthUncertaintyInDeg();
- method public int getBitNumber();
+ method public double getAccumulatedDeltaRangeMeters();
+ method public int getAccumulatedDeltaRangeState();
+ method public double getAccumulatedDeltaRangeUncertaintyMeters();
method public long getCarrierCycles();
- method public float getCarrierFrequencyInHz();
+ method public float getCarrierFrequencyHz();
method public double getCarrierPhase();
method public double getCarrierPhaseUncertainty();
- method public double getCn0InDbHz();
- method public double getCodePhaseInChips();
- method public double getCodePhaseUncertaintyInChips();
- method public byte getConstellationType();
- method public double getDopplerShiftInHz();
- method public double getDopplerShiftUncertaintyInHz();
- method public double getElevationInDeg();
- method public double getElevationUncertaintyInDeg();
- method public byte getLossOfLock();
- method public byte getMultipathIndicator();
- method public double getPseudorangeInMeters();
- method public double getPseudorangeRateInMetersPerSec();
- method public double getPseudorangeRateUncertaintyInMetersPerSec();
- method public double getPseudorangeUncertaintyInMeters();
- method public long getReceivedSvTimeInNs();
- method public long getReceivedSvTimeUncertaintyInNs();
+ method public double getCn0DbHz();
+ method public int getConstellationType();
+ method public int getMultipathIndicator();
+ method public double getPseudorangeRateMetersPerSecond();
+ method public double getPseudorangeRateUncertaintyMetersPerSecond();
+ method public long getReceivedSvTimeNanos();
+ method public long getReceivedSvTimeUncertaintyNanos();
method public double getSnrInDb();
- method public short getState();
- method public short getSvid();
- method public short getTimeFromLastBitInMs();
- method public double getTimeOffsetInNs();
- method public boolean hasAzimuthInDeg();
- method public boolean hasAzimuthUncertaintyInDeg();
- method public boolean hasBitNumber();
+ method public int getState();
+ method public int getSvid();
+ method public double getTimeOffsetNanos();
method public boolean hasCarrierCycles();
- method public boolean hasCarrierFrequencyInHz();
+ method public boolean hasCarrierFrequencyHz();
method public boolean hasCarrierPhase();
method public boolean hasCarrierPhaseUncertainty();
- method public boolean hasCodePhaseInChips();
- method public boolean hasCodePhaseUncertaintyInChips();
- method public boolean hasDopplerShiftInHz();
- method public boolean hasDopplerShiftUncertaintyInHz();
- method public boolean hasElevationInDeg();
- method public boolean hasElevationUncertaintyInDeg();
- method public boolean hasPseudorangeInMeters();
- method public boolean hasPseudorangeUncertaintyInMeters();
method public boolean hasSnrInDb();
- method public boolean hasTimeFromLastBitInMs();
method public boolean isPseudorangeRateCorrected();
- method public boolean isUsedInFix();
method public void reset();
- method public void resetAzimuthInDeg();
- method public void resetAzimuthUncertaintyInDeg();
- method public void resetBitNumber();
method public void resetCarrierCycles();
- method public void resetCarrierFrequencyInHz();
+ method public void resetCarrierFrequencyHz();
method public void resetCarrierPhase();
method public void resetCarrierPhaseUncertainty();
- method public void resetCodePhaseInChips();
- method public void resetCodePhaseUncertaintyInChips();
- method public void resetDopplerShiftInHz();
- method public void resetDopplerShiftUncertaintyInHz();
- method public void resetElevationInDeg();
- method public void resetElevationUncertaintyInDeg();
- method public void resetPseudorangeInMeters();
- method public void resetPseudorangeUncertaintyInMeters();
method public void resetSnrInDb();
- method public void resetTimeFromLastBitInMs();
method public void set(android.location.GnssMeasurement);
- method public void setAccumulatedDeltaRangeInMeters(double);
- method public void setAccumulatedDeltaRangeState(short);
- method public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
- method public void setAzimuthInDeg(double);
- method public void setAzimuthUncertaintyInDeg(double);
- method public void setBitNumber(int);
+ method public void setAccumulatedDeltaRangeMeters(double);
+ method public void setAccumulatedDeltaRangeState(int);
+ method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
method public void setCarrierCycles(long);
- method public void setCarrierFrequencyInHz(float);
+ method public void setCarrierFrequencyHz(float);
method public void setCarrierPhase(double);
method public void setCarrierPhaseUncertainty(double);
- method public void setCn0InDbHz(double);
- method public void setCodePhaseInChips(double);
- method public void setCodePhaseUncertaintyInChips(double);
- method public void setConstellationType(byte);
- method public void setDopplerShiftInHz(double);
- method public void setDopplerShiftUncertaintyInHz(double);
- method public void setElevationInDeg(double);
- method public void setElevationUncertaintyInDeg(double);
- method public void setLossOfLock(byte);
- method public void setMultipathIndicator(byte);
- method public void setPseudorangeInMeters(double);
- method public void setPseudorangeRateInMetersPerSec(double);
- method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
- method public void setPseudorangeUncertaintyInMeters(double);
- method public void setReceivedSvTimeInNs(long);
- method public void setReceivedSvTimeUncertaintyInNs(long);
+ method public void setCn0DbHz(double);
+ method public void setConstellationType(int);
+ method public void setMultipathIndicator(int);
+ method public void setPseudorangeRateMetersPerSecond(double);
+ method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
+ method public void setReceivedSvTimeNanos(long);
+ method public void setReceivedSvTimeUncertaintyNanos(long);
method public void setSnrInDb(double);
- method public void setState(short);
- method public void setSvid(short);
- method public void setTimeFromLastBitInMs(short);
- method public void setTimeOffsetInNs(double);
- method public void setUsedInFix(boolean);
+ method public void setState(int);
+ method public void setSvid(int);
+ method public void setTimeOffsetNanos(double);
method public void writeToParcel(android.os.Parcel, int);
- field public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
- field public static final short ADR_STATE_RESET = 2; // 0x2
- field public static final short ADR_STATE_UNKNOWN = 0; // 0x0
- field public static final short ADR_STATE_VALID = 1; // 0x1
+ field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
+ field public static final int ADR_STATE_RESET = 2; // 0x2
+ field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
+ field public static final int ADR_STATE_VALID = 1; // 0x1
field public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
- field public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
- field public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
- field public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
- field public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
- field public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
- field public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
- field public static final short STATE_BIT_SYNC = 2; // 0x2
- field public static final short STATE_CODE_LOCK = 1; // 0x1
- field public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
- field public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
- field public static final short STATE_TOW_DECODED = 8; // 0x8
- field public static final short STATE_UNKNOWN = 0; // 0x0
- }
-
- public static abstract class GnssMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
+ field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+ field public static final int MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
+ field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+ field public static final int STATE_BIT_SYNC = 2; // 0x2
+ field public static final int STATE_CODE_LOCK = 1; // 0x1
+ field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
+ field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
+ field public static final int STATE_TOW_DECODED = 8; // 0x8
+ field public static final int STATE_UNKNOWN = 0; // 0x0
}
public static abstract class GnssMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
@@ -19329,7 +19271,7 @@
method public java.util.Collection<android.location.GnssMeasurement> getMeasurements();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementsEvent> CREATOR;
- field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+ field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
field public static final int STATUS_READY = 1; // 0x1
}
@@ -19346,34 +19288,34 @@
public final class GnssNavigationMessage implements android.os.Parcelable {
method public int describeContents();
method public byte[] getData();
- method public short getMessageId();
- method public short getStatus();
- method public short getSubmessageId();
- method public short getSvid();
- method public short getType();
+ method public int getMessageId();
+ method public int getStatus();
+ method public int getSubmessageId();
+ method public int getSvid();
+ method public int getType();
method public void reset();
method public void set(android.location.GnssNavigationMessage);
method public void setData(byte[]);
- method public void setMessageId(short);
- method public void setStatus(short);
- method public void setSubmessageId(short);
- method public void setSvid(short);
- method public void setType(short);
+ method public void setMessageId(int);
+ method public void setStatus(int);
+ method public void setSubmessageId(int);
+ method public void setSvid(int);
+ method public void setType(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
- field public static final short MESSAGE_TYPE_BDS_D1 = 1281; // 0x501
- field public static final short MESSAGE_TYPE_BDS_D2 = 1282; // 0x502
- field public static final short MESSAGE_TYPE_GAL_F = 1538; // 0x602
- field public static final short MESSAGE_TYPE_GAL_I = 1537; // 0x601
- field public static final short MESSAGE_TYPE_GLO_L1CA = 769; // 0x301
- field public static final short MESSAGE_TYPE_GPS_CNAV2 = 260; // 0x104
- field public static final short MESSAGE_TYPE_GPS_L1CA = 257; // 0x101
- field public static final short MESSAGE_TYPE_GPS_L2CNAV = 258; // 0x102
- field public static final short MESSAGE_TYPE_GPS_L5CNAV = 259; // 0x103
- field public static final short MESSAGE_TYPE_UNKNOWN = 0; // 0x0
- field public static final short STATUS_PARITY_PASSED = 1; // 0x1
- field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
- field public static final short STATUS_UNKNOWN = 0; // 0x0
+ field public static final int STATUS_PARITY_PASSED = 1; // 0x1
+ field public static final int STATUS_PARITY_REBUILT = 2; // 0x2
+ field public static final int STATUS_UNKNOWN = 0; // 0x0
+ field public static final int TYPE_BDS_D1 = 1281; // 0x501
+ field public static final int TYPE_BDS_D2 = 1282; // 0x502
+ field public static final int TYPE_GAL_F = 1538; // 0x602
+ field public static final int TYPE_GAL_I = 1537; // 0x601
+ field public static final int TYPE_GLO_L1CA = 769; // 0x301
+ field public static final int TYPE_GPS_CNAV2 = 260; // 0x104
+ field public static final int TYPE_GPS_L1CA = 257; // 0x101
+ field public static final int TYPE_GPS_L2CNAV = 258; // 0x102
+ field public static final int TYPE_GPS_L5CNAV = 259; // 0x103
+ field public static final int TYPE_UNKNOWN = 0; // 0x0
}
public static abstract class GnssNavigationMessage.GnssNavigationMessageType implements java.lang.annotation.Annotation {
@@ -19385,7 +19327,7 @@
method public android.location.GnssNavigationMessage getNavigationMessage();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessageEvent> CREATOR;
- field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+ field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
field public static final int STATUS_READY = 1; // 0x1
}
@@ -19404,22 +19346,22 @@
}
public final class GnssStatus {
- method public float getAzimuth(int);
- method public byte getConstellationType(int);
- method public float getElevation(int);
+ method public float getAzimuthDegrees(int);
+ method public float getCn0DbHz(int);
+ method public int getConstellationType(int);
+ method public float getElevationDegrees(int);
method public int getNumSatellites();
- method public float getSnr(int);
method public int getSvid(int);
method public boolean hasAlmanac(int);
method public boolean hasEphemeris(int);
method public boolean usedInFix(int);
- field public static final byte CONSTELLATION_BEIDOU = 5; // 0x5
- field public static final byte CONSTELLATION_GALILEO = 6; // 0x6
- field public static final byte CONSTELLATION_GLONASS = 3; // 0x3
- field public static final byte CONSTELLATION_GPS = 1; // 0x1
- field public static final byte CONSTELLATION_QZSS = 4; // 0x4
- field public static final byte CONSTELLATION_SBAS = 2; // 0x2
- field public static final byte CONSTELLATION_UNKNOWN = 0; // 0x0
+ field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final int CONSTELLATION_GPS = 1; // 0x1
+ field public static final int CONSTELLATION_QZSS = 4; // 0x4
+ field public static final int CONSTELLATION_SBAS = 2; // 0x2
+ field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
}
public static abstract class GnssStatus.ConstellationType implements java.lang.annotation.Annotation {
@@ -19534,8 +19476,8 @@
method public java.util.List<java.lang.String> getProviders(boolean);
method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
method public boolean isProviderEnabled(java.lang.String);
- method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
- method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
+ method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
+ method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback, android.os.Handler);
method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
@@ -19560,7 +19502,7 @@
method public void setTestProviderEnabled(java.lang.String, boolean);
method public void setTestProviderLocation(java.lang.String, android.location.Location);
method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
- method public void unregisterGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
+ method public void unregisterGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
method public void unregisterGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
method public void unregisterGnssStatusCallback(android.location.GnssStatusCallback);
field public static final java.lang.String GPS_PROVIDER = "gps";
@@ -19924,7 +19866,7 @@
public static abstract class AudioManager.AudioRecordingCallback {
ctor public AudioManager.AudioRecordingCallback();
- method public void onRecordConfigChanged();
+ method public void onRecordConfigChanged(android.media.AudioRecordConfiguration[]);
}
public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -20992,6 +20934,7 @@
field public static final java.lang.String KEY_SLICE_HEIGHT = "slice-height";
field public static final java.lang.String KEY_STRIDE = "stride";
field public static final java.lang.String KEY_TEMPORAL_LAYERING = "ts-schema";
+ field public static final java.lang.String KEY_TRACK_ID = "track-id";
field public static final java.lang.String KEY_WIDTH = "width";
field public static final java.lang.String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
field public static final java.lang.String MIMETYPE_AUDIO_AC3 = "audio/ac3";
@@ -29104,6 +29047,8 @@
ctor public Process();
method public static final long getElapsedCpuTime();
method public static final int getGidForName(java.lang.String);
+ method public static final long getStartElapsedRealtime();
+ method public static final long getStartUptimeMillis();
method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
method public static final int getUidForName(java.lang.String);
method public static final boolean is64Bit();
@@ -31769,6 +31714,7 @@
public static final class DocumentsContract.Root {
field public static final java.lang.String COLUMN_AVAILABLE_BYTES = "available_bytes";
+ field public static final java.lang.String COLUMN_CAPACITY_BYTES = "capacity_bytes";
field public static final java.lang.String COLUMN_DOCUMENT_ID = "document_id";
field public static final java.lang.String COLUMN_FLAGS = "flags";
field public static final java.lang.String COLUMN_ICON = "icon";
@@ -34291,7 +34237,8 @@
ctor public CarrierMessagingService();
method public android.os.IBinder onBind(android.content.Intent);
method public void onDownloadMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
- method public void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+ method public deprecated void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+ method public void onReceiveTextSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
method public deprecated void onSendDataSms(byte[], int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
method public void onSendDataSms(byte[], int, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
method public void onSendMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMmsResult>);
@@ -34302,6 +34249,9 @@
field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2
field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0
field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
+ field public static final int RECEIVE_OPTIONS_DEFAULT = 0; // 0x0
+ field public static final int RECEIVE_OPTIONS_DROP = 1; // 0x1
+ field public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE = 2; // 0x2
field public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1; // 0x1
field public static final int SEND_STATUS_ERROR = 2; // 0x2
field public static final int SEND_STATUS_OK = 0; // 0x0
@@ -38528,7 +38478,6 @@
method public boolean hasNext();
method public java.util.Iterator<java.lang.String> iterator();
method public java.lang.String next();
- method public void remove();
method public void setString(java.lang.String);
}
@@ -40140,6 +40089,7 @@
method public int describeContents();
method public static android.util.LocaleList forLanguageTags(java.lang.String);
method public java.util.Locale get(int);
+ method public static android.util.LocaleList getAdjustedDefault();
method public static android.util.LocaleList getDefault();
method public static android.util.LocaleList getEmptyLocaleList();
method public java.util.Locale getFirstMatch(java.lang.String[]);
@@ -57763,9 +57713,10 @@
}
public abstract interface Iterator {
+ method public default void forEachRemaining(java.util.function.Consumer<? super E>);
method public abstract boolean hasNext();
method public abstract E next();
- method public abstract void remove();
+ method public default void remove();
}
public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
@@ -58068,6 +58019,79 @@
method public abstract void update(java.util.Observable, java.lang.Object);
}
+ public final class Optional {
+ method public static java.util.Optional<T> empty();
+ method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
+ method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
+ method public T get();
+ method public void ifPresent(java.util.function.Consumer<? super T>);
+ method public boolean isPresent();
+ method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
+ method public static java.util.Optional<T> of(T);
+ method public static java.util.Optional<T> ofNullable(T);
+ method public T orElse(T);
+ method public T orElseGet(java.util.function.Supplier<? extends T>);
+ method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
+ }
+
+ public final class OptionalDouble {
+ method public static java.util.OptionalDouble empty();
+ method public double getAsDouble();
+ method public void ifPresent(java.util.function.DoubleConsumer);
+ method public boolean isPresent();
+ method public static java.util.OptionalDouble of(double);
+ method public double orElse(double);
+ method public double orElseGet(java.util.function.DoubleSupplier);
+ method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+ }
+
+ public final class OptionalInt {
+ method public static java.util.OptionalInt empty();
+ method public int getAsInt();
+ method public void ifPresent(java.util.function.IntConsumer);
+ method public boolean isPresent();
+ method public static java.util.OptionalInt of(int);
+ method public int orElse(int);
+ method public int orElseGet(java.util.function.IntSupplier);
+ method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+ }
+
+ public final class OptionalLong {
+ method public static java.util.OptionalLong empty();
+ method public long getAsLong();
+ method public void ifPresent(java.util.function.LongConsumer);
+ method public boolean isPresent();
+ method public static java.util.OptionalLong of(long);
+ method public long orElse(long);
+ method public long orElseGet(java.util.function.LongSupplier);
+ method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+ }
+
+ public abstract interface PrimitiveIterator implements java.util.Iterator {
+ method public abstract void forEachRemaining(T_CONS);
+ }
+
+ public static abstract interface PrimitiveIterator.OfDouble implements java.util.PrimitiveIterator {
+ method public default void forEachRemaining(java.util.function.DoubleConsumer);
+ method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Double>);
+ method public default java.lang.Double next();
+ method public abstract double nextDouble();
+ }
+
+ public static abstract interface PrimitiveIterator.OfInt implements java.util.PrimitiveIterator {
+ method public default void forEachRemaining(java.util.function.IntConsumer);
+ method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Integer>);
+ method public default java.lang.Integer next();
+ method public abstract int nextInt();
+ }
+
+ public static abstract interface PrimitiveIterator.OfLong implements java.util.PrimitiveIterator {
+ method public default void forEachRemaining(java.util.function.LongConsumer);
+ method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Long>);
+ method public default java.lang.Long next();
+ method public abstract long nextLong();
+ }
+
public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
ctor public PriorityQueue();
ctor public PriorityQueue(int);
@@ -58239,7 +58263,6 @@
method public short nextShort();
method public short nextShort(int);
method public int radix();
- method public void remove();
method public java.util.Scanner reset();
method public java.util.Scanner skip(java.util.regex.Pattern);
method public java.util.Scanner skip(java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index 1a2c854..9a84d1a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5390,7 +5390,7 @@
}
public static class NotificationManager.Policy implements android.os.Parcelable {
- ctor public deprecated NotificationManager.Policy(int, int, int);
+ ctor public NotificationManager.Policy(int, int, int);
ctor public NotificationManager.Policy(int, int, int, int);
method public int describeContents();
method public static java.lang.String priorityCategoriesToString(int);
@@ -5843,6 +5843,7 @@
public class WallpaperManager {
method public void clear() throws java.io.IOException;
+ method public void clear(int) throws java.io.IOException;
method public void clearWallpaper();
method public void clearWallpaper(int, int);
method public void clearWallpaperOffsets(android.os.IBinder);
@@ -10185,6 +10186,8 @@
field public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103; // 0xffffff99
field public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102; // 0xffffff9a
field public static final int INSTALL_SUCCEEDED = 1; // 0x1
+ field public static final int INTENT_FILTER_VERIFICATION_FAILURE = -1; // 0xffffffff
+ field public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1; // 0x1
field public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
field public static final int MATCH_ALL = 131072; // 0x20000
field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
@@ -10857,7 +10860,6 @@
method public boolean hasNext();
method public java.util.Iterator<android.database.CursorJoiner.Result> iterator();
method public android.database.CursorJoiner.Result next();
- method public void remove();
}
public static final class CursorJoiner.Result extends java.lang.Enum {
@@ -20326,168 +20328,110 @@
public final class GnssClock implements android.os.Parcelable {
method public int describeContents();
- method public double getBiasInNs();
- method public double getBiasUncertaintyInNs();
- method public double getDriftInNsPerSec();
- method public double getDriftUncertaintyInNsPerSec();
- method public long getFullBiasInNs();
+ method public double getBiasNanos();
+ method public double getBiasUncertaintyNanos();
+ method public double getDriftNanosPerSecond();
+ method public double getDriftUncertaintyNanosPerSecond();
+ method public long getFullBiasNanos();
method public int getHardwareClockDiscontinuityCount();
- method public short getLeapSecond();
- method public long getTimeInNs();
- method public double getTimeUncertaintyInNs();
- method public boolean hasBiasInNs();
- method public boolean hasBiasUncertaintyInNs();
- method public boolean hasDriftInNsPerSec();
- method public boolean hasDriftUncertaintyInNsPerSec();
- method public boolean hasFullBiasInNs();
+ method public int getLeapSecond();
+ method public long getTimeNanos();
+ method public double getTimeUncertaintyNanos();
+ method public boolean hasBiasNanos();
+ method public boolean hasBiasUncertaintyNanos();
+ method public boolean hasDriftNanosPerSecond();
+ method public boolean hasDriftUncertaintyNanosPerSecond();
+ method public boolean hasFullBiasNanos();
method public boolean hasLeapSecond();
- method public boolean hasTimeUncertaintyInNs();
+ method public boolean hasTimeUncertaintyNanos();
method public void reset();
- method public void resetBiasInNs();
- method public void resetBiasUncertaintyInNs();
- method public void resetDriftInNsPerSec();
- method public void resetDriftUncertaintyInNsPerSec();
- method public void resetFullBiasInNs();
+ method public void resetBiasNanos();
+ method public void resetBiasUncertaintyNanos();
+ method public void resetDriftNanosPerSecond();
+ method public void resetDriftUncertaintyNanosPerSecond();
+ method public void resetFullBiasNanos();
method public void resetLeapSecond();
- method public void resetTimeUncertaintyInNs();
+ method public void resetTimeUncertaintyNanos();
method public void set(android.location.GnssClock);
- method public void setBiasInNs(double);
- method public void setBiasUncertaintyInNs(double);
- method public void setDriftInNsPerSec(double);
- method public void setDriftUncertaintyInNsPerSec(double);
- method public void setFullBiasInNs(long);
+ method public void setBiasNanos(double);
+ method public void setBiasUncertaintyNanos(double);
+ method public void setDriftNanosPerSecond(double);
+ method public void setDriftUncertaintyNanosPerSecond(double);
+ method public void setFullBiasNanos(long);
method public void setHardwareClockDiscontinuityCount(int);
- method public void setLeapSecond(short);
- method public void setTimeInNs(long);
- method public void setTimeUncertaintyInNs(double);
+ method public void setLeapSecond(int);
+ method public void setTimeNanos(long);
+ method public void setTimeUncertaintyNanos(double);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
}
public final class GnssMeasurement implements android.os.Parcelable {
method public int describeContents();
- method public double getAccumulatedDeltaRangeInMeters();
- method public short getAccumulatedDeltaRangeState();
- method public double getAccumulatedDeltaRangeUncertaintyInMeters();
- method public double getAzimuthInDeg();
- method public double getAzimuthUncertaintyInDeg();
- method public int getBitNumber();
+ method public double getAccumulatedDeltaRangeMeters();
+ method public int getAccumulatedDeltaRangeState();
+ method public double getAccumulatedDeltaRangeUncertaintyMeters();
method public long getCarrierCycles();
- method public float getCarrierFrequencyInHz();
+ method public float getCarrierFrequencyHz();
method public double getCarrierPhase();
method public double getCarrierPhaseUncertainty();
- method public double getCn0InDbHz();
- method public double getCodePhaseInChips();
- method public double getCodePhaseUncertaintyInChips();
- method public byte getConstellationType();
- method public double getDopplerShiftInHz();
- method public double getDopplerShiftUncertaintyInHz();
- method public double getElevationInDeg();
- method public double getElevationUncertaintyInDeg();
- method public byte getLossOfLock();
- method public byte getMultipathIndicator();
- method public double getPseudorangeInMeters();
- method public double getPseudorangeRateInMetersPerSec();
- method public double getPseudorangeRateUncertaintyInMetersPerSec();
- method public double getPseudorangeUncertaintyInMeters();
- method public long getReceivedSvTimeInNs();
- method public long getReceivedSvTimeUncertaintyInNs();
+ method public double getCn0DbHz();
+ method public int getConstellationType();
+ method public int getMultipathIndicator();
+ method public double getPseudorangeRateMetersPerSecond();
+ method public double getPseudorangeRateUncertaintyMetersPerSecond();
+ method public long getReceivedSvTimeNanos();
+ method public long getReceivedSvTimeUncertaintyNanos();
method public double getSnrInDb();
- method public short getState();
- method public short getSvid();
- method public short getTimeFromLastBitInMs();
- method public double getTimeOffsetInNs();
- method public boolean hasAzimuthInDeg();
- method public boolean hasAzimuthUncertaintyInDeg();
- method public boolean hasBitNumber();
+ method public int getState();
+ method public int getSvid();
+ method public double getTimeOffsetNanos();
method public boolean hasCarrierCycles();
- method public boolean hasCarrierFrequencyInHz();
+ method public boolean hasCarrierFrequencyHz();
method public boolean hasCarrierPhase();
method public boolean hasCarrierPhaseUncertainty();
- method public boolean hasCodePhaseInChips();
- method public boolean hasCodePhaseUncertaintyInChips();
- method public boolean hasDopplerShiftInHz();
- method public boolean hasDopplerShiftUncertaintyInHz();
- method public boolean hasElevationInDeg();
- method public boolean hasElevationUncertaintyInDeg();
- method public boolean hasPseudorangeInMeters();
- method public boolean hasPseudorangeUncertaintyInMeters();
method public boolean hasSnrInDb();
- method public boolean hasTimeFromLastBitInMs();
method public boolean isPseudorangeRateCorrected();
- method public boolean isUsedInFix();
method public void reset();
- method public void resetAzimuthInDeg();
- method public void resetAzimuthUncertaintyInDeg();
- method public void resetBitNumber();
method public void resetCarrierCycles();
- method public void resetCarrierFrequencyInHz();
+ method public void resetCarrierFrequencyHz();
method public void resetCarrierPhase();
method public void resetCarrierPhaseUncertainty();
- method public void resetCodePhaseInChips();
- method public void resetCodePhaseUncertaintyInChips();
- method public void resetDopplerShiftInHz();
- method public void resetDopplerShiftUncertaintyInHz();
- method public void resetElevationInDeg();
- method public void resetElevationUncertaintyInDeg();
- method public void resetPseudorangeInMeters();
- method public void resetPseudorangeUncertaintyInMeters();
method public void resetSnrInDb();
- method public void resetTimeFromLastBitInMs();
method public void set(android.location.GnssMeasurement);
- method public void setAccumulatedDeltaRangeInMeters(double);
- method public void setAccumulatedDeltaRangeState(short);
- method public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
- method public void setAzimuthInDeg(double);
- method public void setAzimuthUncertaintyInDeg(double);
- method public void setBitNumber(int);
+ method public void setAccumulatedDeltaRangeMeters(double);
+ method public void setAccumulatedDeltaRangeState(int);
+ method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
method public void setCarrierCycles(long);
- method public void setCarrierFrequencyInHz(float);
+ method public void setCarrierFrequencyHz(float);
method public void setCarrierPhase(double);
method public void setCarrierPhaseUncertainty(double);
- method public void setCn0InDbHz(double);
- method public void setCodePhaseInChips(double);
- method public void setCodePhaseUncertaintyInChips(double);
- method public void setConstellationType(byte);
- method public void setDopplerShiftInHz(double);
- method public void setDopplerShiftUncertaintyInHz(double);
- method public void setElevationInDeg(double);
- method public void setElevationUncertaintyInDeg(double);
- method public void setLossOfLock(byte);
- method public void setMultipathIndicator(byte);
- method public void setPseudorangeInMeters(double);
- method public void setPseudorangeRateInMetersPerSec(double);
- method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
- method public void setPseudorangeUncertaintyInMeters(double);
- method public void setReceivedSvTimeInNs(long);
- method public void setReceivedSvTimeUncertaintyInNs(long);
+ method public void setCn0DbHz(double);
+ method public void setConstellationType(int);
+ method public void setMultipathIndicator(int);
+ method public void setPseudorangeRateMetersPerSecond(double);
+ method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
+ method public void setReceivedSvTimeNanos(long);
+ method public void setReceivedSvTimeUncertaintyNanos(long);
method public void setSnrInDb(double);
- method public void setState(short);
- method public void setSvid(short);
- method public void setTimeFromLastBitInMs(short);
- method public void setTimeOffsetInNs(double);
- method public void setUsedInFix(boolean);
+ method public void setState(int);
+ method public void setSvid(int);
+ method public void setTimeOffsetNanos(double);
method public void writeToParcel(android.os.Parcel, int);
- field public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
- field public static final short ADR_STATE_RESET = 2; // 0x2
- field public static final short ADR_STATE_UNKNOWN = 0; // 0x0
- field public static final short ADR_STATE_VALID = 1; // 0x1
+ field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
+ field public static final int ADR_STATE_RESET = 2; // 0x2
+ field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
+ field public static final int ADR_STATE_VALID = 1; // 0x1
field public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
- field public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
- field public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
- field public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
- field public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
- field public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
- field public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
- field public static final short STATE_BIT_SYNC = 2; // 0x2
- field public static final short STATE_CODE_LOCK = 1; // 0x1
- field public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
- field public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
- field public static final short STATE_TOW_DECODED = 8; // 0x8
- field public static final short STATE_UNKNOWN = 0; // 0x0
- }
-
- public static abstract class GnssMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
+ field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+ field public static final int MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
+ field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+ field public static final int STATE_BIT_SYNC = 2; // 0x2
+ field public static final int STATE_CODE_LOCK = 1; // 0x1
+ field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
+ field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
+ field public static final int STATE_TOW_DECODED = 8; // 0x8
+ field public static final int STATE_UNKNOWN = 0; // 0x0
}
public static abstract class GnssMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
@@ -20500,7 +20444,7 @@
method public java.util.Collection<android.location.GnssMeasurement> getMeasurements();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementsEvent> CREATOR;
- field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+ field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
field public static final int STATUS_READY = 1; // 0x1
}
@@ -20517,34 +20461,34 @@
public final class GnssNavigationMessage implements android.os.Parcelable {
method public int describeContents();
method public byte[] getData();
- method public short getMessageId();
- method public short getStatus();
- method public short getSubmessageId();
- method public short getSvid();
- method public short getType();
+ method public int getMessageId();
+ method public int getStatus();
+ method public int getSubmessageId();
+ method public int getSvid();
+ method public int getType();
method public void reset();
method public void set(android.location.GnssNavigationMessage);
method public void setData(byte[]);
- method public void setMessageId(short);
- method public void setStatus(short);
- method public void setSubmessageId(short);
- method public void setSvid(short);
- method public void setType(short);
+ method public void setMessageId(int);
+ method public void setStatus(int);
+ method public void setSubmessageId(int);
+ method public void setSvid(int);
+ method public void setType(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
- field public static final short MESSAGE_TYPE_BDS_D1 = 1281; // 0x501
- field public static final short MESSAGE_TYPE_BDS_D2 = 1282; // 0x502
- field public static final short MESSAGE_TYPE_GAL_F = 1538; // 0x602
- field public static final short MESSAGE_TYPE_GAL_I = 1537; // 0x601
- field public static final short MESSAGE_TYPE_GLO_L1CA = 769; // 0x301
- field public static final short MESSAGE_TYPE_GPS_CNAV2 = 260; // 0x104
- field public static final short MESSAGE_TYPE_GPS_L1CA = 257; // 0x101
- field public static final short MESSAGE_TYPE_GPS_L2CNAV = 258; // 0x102
- field public static final short MESSAGE_TYPE_GPS_L5CNAV = 259; // 0x103
- field public static final short MESSAGE_TYPE_UNKNOWN = 0; // 0x0
- field public static final short STATUS_PARITY_PASSED = 1; // 0x1
- field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
- field public static final short STATUS_UNKNOWN = 0; // 0x0
+ field public static final int STATUS_PARITY_PASSED = 1; // 0x1
+ field public static final int STATUS_PARITY_REBUILT = 2; // 0x2
+ field public static final int STATUS_UNKNOWN = 0; // 0x0
+ field public static final int TYPE_BDS_D1 = 1281; // 0x501
+ field public static final int TYPE_BDS_D2 = 1282; // 0x502
+ field public static final int TYPE_GAL_F = 1538; // 0x602
+ field public static final int TYPE_GAL_I = 1537; // 0x601
+ field public static final int TYPE_GLO_L1CA = 769; // 0x301
+ field public static final int TYPE_GPS_CNAV2 = 260; // 0x104
+ field public static final int TYPE_GPS_L1CA = 257; // 0x101
+ field public static final int TYPE_GPS_L2CNAV = 258; // 0x102
+ field public static final int TYPE_GPS_L5CNAV = 259; // 0x103
+ field public static final int TYPE_UNKNOWN = 0; // 0x0
}
public static abstract class GnssNavigationMessage.GnssNavigationMessageType implements java.lang.annotation.Annotation {
@@ -20556,7 +20500,7 @@
method public android.location.GnssNavigationMessage getNavigationMessage();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessageEvent> CREATOR;
- field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+ field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
field public static final int STATUS_READY = 1; // 0x1
}
@@ -20575,22 +20519,22 @@
}
public final class GnssStatus {
- method public float getAzimuth(int);
- method public byte getConstellationType(int);
- method public float getElevation(int);
+ method public float getAzimuthDegrees(int);
+ method public float getCn0DbHz(int);
+ method public int getConstellationType(int);
+ method public float getElevationDegrees(int);
method public int getNumSatellites();
- method public float getSnr(int);
method public int getSvid(int);
method public boolean hasAlmanac(int);
method public boolean hasEphemeris(int);
method public boolean usedInFix(int);
- field public static final byte CONSTELLATION_BEIDOU = 5; // 0x5
- field public static final byte CONSTELLATION_GALILEO = 6; // 0x6
- field public static final byte CONSTELLATION_GLONASS = 3; // 0x3
- field public static final byte CONSTELLATION_GPS = 1; // 0x1
- field public static final byte CONSTELLATION_QZSS = 4; // 0x4
- field public static final byte CONSTELLATION_SBAS = 2; // 0x2
- field public static final byte CONSTELLATION_UNKNOWN = 0; // 0x0
+ field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final int CONSTELLATION_GPS = 1; // 0x1
+ field public static final int CONSTELLATION_QZSS = 4; // 0x4
+ field public static final int CONSTELLATION_SBAS = 2; // 0x2
+ field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
}
public static abstract class GnssStatus.ConstellationType implements java.lang.annotation.Annotation {
@@ -20952,8 +20896,8 @@
method public java.util.List<java.lang.String> getProviders(boolean);
method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
method public boolean isProviderEnabled(java.lang.String);
- method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
- method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
+ method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
+ method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback, android.os.Handler);
method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
@@ -20982,7 +20926,7 @@
method public void setTestProviderEnabled(java.lang.String, boolean);
method public void setTestProviderLocation(java.lang.String, android.location.Location);
method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
- method public void unregisterGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
+ method public void unregisterGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
method public void unregisterGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
method public void unregisterGnssStatusCallback(android.location.GnssStatusCallback);
field public static final java.lang.String GPS_PROVIDER = "gps";
@@ -21411,7 +21355,7 @@
public static abstract class AudioManager.AudioRecordingCallback {
ctor public AudioManager.AudioRecordingCallback();
- method public void onRecordConfigChanged();
+ method public void onRecordConfigChanged(android.media.AudioRecordConfiguration[]);
}
public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -22482,6 +22426,7 @@
field public static final java.lang.String KEY_SLICE_HEIGHT = "slice-height";
field public static final java.lang.String KEY_STRIDE = "stride";
field public static final java.lang.String KEY_TEMPORAL_LAYERING = "ts-schema";
+ field public static final java.lang.String KEY_TRACK_ID = "track-id";
field public static final java.lang.String KEY_WIDTH = "width";
field public static final java.lang.String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
field public static final java.lang.String MIMETYPE_AUDIO_AC3 = "audio/ac3";
@@ -26719,7 +26664,6 @@
method public boolean reconnect();
method public boolean removeNetwork(int);
method public boolean saveConfiguration();
- method public boolean setMetered(int, boolean);
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
@@ -31396,6 +31340,8 @@
ctor public Process();
method public static final long getElapsedCpuTime();
method public static final int getGidForName(java.lang.String);
+ method public static final long getStartElapsedRealtime();
+ method public static final long getStartUptimeMillis();
method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
method public static final int getUidForName(java.lang.String);
method public static final boolean is64Bit();
@@ -34153,6 +34099,7 @@
public static final class DocumentsContract.Root {
field public static final java.lang.String COLUMN_AVAILABLE_BYTES = "available_bytes";
+ field public static final java.lang.String COLUMN_CAPACITY_BYTES = "capacity_bytes";
field public static final java.lang.String COLUMN_DOCUMENT_ID = "document_id";
field public static final java.lang.String COLUMN_FLAGS = "flags";
field public static final java.lang.String COLUMN_ICON = "icon";
@@ -36780,7 +36727,8 @@
ctor public CarrierMessagingService();
method public android.os.IBinder onBind(android.content.Intent);
method public void onDownloadMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
- method public void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+ method public deprecated void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+ method public void onReceiveTextSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
method public deprecated void onSendDataSms(byte[], int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
method public void onSendDataSms(byte[], int, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
method public void onSendMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMmsResult>);
@@ -36791,6 +36739,9 @@
field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2
field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0
field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
+ field public static final int RECEIVE_OPTIONS_DEFAULT = 0; // 0x0
+ field public static final int RECEIVE_OPTIONS_DROP = 1; // 0x1
+ field public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE = 2; // 0x2
field public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1; // 0x1
field public static final int SEND_STATUS_ERROR = 2; // 0x2
field public static final int SEND_STATUS_OK = 0; // 0x0
@@ -41294,7 +41245,6 @@
method public boolean hasNext();
method public java.util.Iterator<java.lang.String> iterator();
method public java.lang.String next();
- method public void remove();
method public void setString(java.lang.String);
}
@@ -42906,6 +42856,7 @@
method public int describeContents();
method public static android.util.LocaleList forLanguageTags(java.lang.String);
method public java.util.Locale get(int);
+ method public static android.util.LocaleList getAdjustedDefault();
method public static android.util.LocaleList getDefault();
method public static android.util.LocaleList getEmptyLocaleList();
method public java.util.Locale getFirstMatch(java.lang.String[]);
@@ -60866,9 +60817,10 @@
}
public abstract interface Iterator {
+ method public default void forEachRemaining(java.util.function.Consumer<? super E>);
method public abstract boolean hasNext();
method public abstract E next();
- method public abstract void remove();
+ method public default void remove();
}
public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
@@ -61171,6 +61123,79 @@
method public abstract void update(java.util.Observable, java.lang.Object);
}
+ public final class Optional {
+ method public static java.util.Optional<T> empty();
+ method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
+ method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
+ method public T get();
+ method public void ifPresent(java.util.function.Consumer<? super T>);
+ method public boolean isPresent();
+ method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
+ method public static java.util.Optional<T> of(T);
+ method public static java.util.Optional<T> ofNullable(T);
+ method public T orElse(T);
+ method public T orElseGet(java.util.function.Supplier<? extends T>);
+ method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
+ }
+
+ public final class OptionalDouble {
+ method public static java.util.OptionalDouble empty();
+ method public double getAsDouble();
+ method public void ifPresent(java.util.function.DoubleConsumer);
+ method public boolean isPresent();
+ method public static java.util.OptionalDouble of(double);
+ method public double orElse(double);
+ method public double orElseGet(java.util.function.DoubleSupplier);
+ method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+ }
+
+ public final class OptionalInt {
+ method public static java.util.OptionalInt empty();
+ method public int getAsInt();
+ method public void ifPresent(java.util.function.IntConsumer);
+ method public boolean isPresent();
+ method public static java.util.OptionalInt of(int);
+ method public int orElse(int);
+ method public int orElseGet(java.util.function.IntSupplier);
+ method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+ }
+
+ public final class OptionalLong {
+ method public static java.util.OptionalLong empty();
+ method public long getAsLong();
+ method public void ifPresent(java.util.function.LongConsumer);
+ method public boolean isPresent();
+ method public static java.util.OptionalLong of(long);
+ method public long orElse(long);
+ method public long orElseGet(java.util.function.LongSupplier);
+ method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+ }
+
+ public abstract interface PrimitiveIterator implements java.util.Iterator {
+ method public abstract void forEachRemaining(T_CONS);
+ }
+
+ public static abstract interface PrimitiveIterator.OfDouble implements java.util.PrimitiveIterator {
+ method public default void forEachRemaining(java.util.function.DoubleConsumer);
+ method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Double>);
+ method public default java.lang.Double next();
+ method public abstract double nextDouble();
+ }
+
+ public static abstract interface PrimitiveIterator.OfInt implements java.util.PrimitiveIterator {
+ method public default void forEachRemaining(java.util.function.IntConsumer);
+ method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Integer>);
+ method public default java.lang.Integer next();
+ method public abstract int nextInt();
+ }
+
+ public static abstract interface PrimitiveIterator.OfLong implements java.util.PrimitiveIterator {
+ method public default void forEachRemaining(java.util.function.LongConsumer);
+ method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Long>);
+ method public default java.lang.Long next();
+ method public abstract long nextLong();
+ }
+
public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
ctor public PriorityQueue();
ctor public PriorityQueue(int);
@@ -61342,7 +61367,6 @@
method public short nextShort();
method public short nextShort(int);
method public int radix();
- method public void remove();
method public java.util.Scanner reset();
method public java.util.Scanner skip(java.util.regex.Pattern);
method public java.util.Scanner skip(java.lang.String);
diff --git a/api/test-current.txt b/api/test-current.txt
index 1039fed..f18f4e1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5258,7 +5258,7 @@
}
public static class NotificationManager.Policy implements android.os.Parcelable {
- ctor public deprecated NotificationManager.Policy(int, int, int);
+ ctor public NotificationManager.Policy(int, int, int);
ctor public NotificationManager.Policy(int, int, int, int);
method public int describeContents();
method public static java.lang.String priorityCategoriesToString(int);
@@ -5715,6 +5715,7 @@
public class WallpaperManager {
method public void clear() throws java.io.IOException;
+ method public void clear(int) throws java.io.IOException;
method public void clearWallpaperOffsets(android.os.IBinder);
method public void forgetLoadedWallpaper();
method public android.graphics.drawable.Drawable getBuiltInDrawable();
@@ -10475,7 +10476,6 @@
method public boolean hasNext();
method public java.util.Iterator<android.database.CursorJoiner.Result> iterator();
method public android.database.CursorJoiner.Result next();
- method public void remove();
}
public static final class CursorJoiner.Result extends java.lang.Enum {
@@ -19165,168 +19165,110 @@
public final class GnssClock implements android.os.Parcelable {
method public int describeContents();
- method public double getBiasInNs();
- method public double getBiasUncertaintyInNs();
- method public double getDriftInNsPerSec();
- method public double getDriftUncertaintyInNsPerSec();
- method public long getFullBiasInNs();
+ method public double getBiasNanos();
+ method public double getBiasUncertaintyNanos();
+ method public double getDriftNanosPerSecond();
+ method public double getDriftUncertaintyNanosPerSecond();
+ method public long getFullBiasNanos();
method public int getHardwareClockDiscontinuityCount();
- method public short getLeapSecond();
- method public long getTimeInNs();
- method public double getTimeUncertaintyInNs();
- method public boolean hasBiasInNs();
- method public boolean hasBiasUncertaintyInNs();
- method public boolean hasDriftInNsPerSec();
- method public boolean hasDriftUncertaintyInNsPerSec();
- method public boolean hasFullBiasInNs();
+ method public int getLeapSecond();
+ method public long getTimeNanos();
+ method public double getTimeUncertaintyNanos();
+ method public boolean hasBiasNanos();
+ method public boolean hasBiasUncertaintyNanos();
+ method public boolean hasDriftNanosPerSecond();
+ method public boolean hasDriftUncertaintyNanosPerSecond();
+ method public boolean hasFullBiasNanos();
method public boolean hasLeapSecond();
- method public boolean hasTimeUncertaintyInNs();
+ method public boolean hasTimeUncertaintyNanos();
method public void reset();
- method public void resetBiasInNs();
- method public void resetBiasUncertaintyInNs();
- method public void resetDriftInNsPerSec();
- method public void resetDriftUncertaintyInNsPerSec();
- method public void resetFullBiasInNs();
+ method public void resetBiasNanos();
+ method public void resetBiasUncertaintyNanos();
+ method public void resetDriftNanosPerSecond();
+ method public void resetDriftUncertaintyNanosPerSecond();
+ method public void resetFullBiasNanos();
method public void resetLeapSecond();
- method public void resetTimeUncertaintyInNs();
+ method public void resetTimeUncertaintyNanos();
method public void set(android.location.GnssClock);
- method public void setBiasInNs(double);
- method public void setBiasUncertaintyInNs(double);
- method public void setDriftInNsPerSec(double);
- method public void setDriftUncertaintyInNsPerSec(double);
- method public void setFullBiasInNs(long);
+ method public void setBiasNanos(double);
+ method public void setBiasUncertaintyNanos(double);
+ method public void setDriftNanosPerSecond(double);
+ method public void setDriftUncertaintyNanosPerSecond(double);
+ method public void setFullBiasNanos(long);
method public void setHardwareClockDiscontinuityCount(int);
- method public void setLeapSecond(short);
- method public void setTimeInNs(long);
- method public void setTimeUncertaintyInNs(double);
+ method public void setLeapSecond(int);
+ method public void setTimeNanos(long);
+ method public void setTimeUncertaintyNanos(double);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
}
public final class GnssMeasurement implements android.os.Parcelable {
method public int describeContents();
- method public double getAccumulatedDeltaRangeInMeters();
- method public short getAccumulatedDeltaRangeState();
- method public double getAccumulatedDeltaRangeUncertaintyInMeters();
- method public double getAzimuthInDeg();
- method public double getAzimuthUncertaintyInDeg();
- method public int getBitNumber();
+ method public double getAccumulatedDeltaRangeMeters();
+ method public int getAccumulatedDeltaRangeState();
+ method public double getAccumulatedDeltaRangeUncertaintyMeters();
method public long getCarrierCycles();
- method public float getCarrierFrequencyInHz();
+ method public float getCarrierFrequencyHz();
method public double getCarrierPhase();
method public double getCarrierPhaseUncertainty();
- method public double getCn0InDbHz();
- method public double getCodePhaseInChips();
- method public double getCodePhaseUncertaintyInChips();
- method public byte getConstellationType();
- method public double getDopplerShiftInHz();
- method public double getDopplerShiftUncertaintyInHz();
- method public double getElevationInDeg();
- method public double getElevationUncertaintyInDeg();
- method public byte getLossOfLock();
- method public byte getMultipathIndicator();
- method public double getPseudorangeInMeters();
- method public double getPseudorangeRateInMetersPerSec();
- method public double getPseudorangeRateUncertaintyInMetersPerSec();
- method public double getPseudorangeUncertaintyInMeters();
- method public long getReceivedSvTimeInNs();
- method public long getReceivedSvTimeUncertaintyInNs();
+ method public double getCn0DbHz();
+ method public int getConstellationType();
+ method public int getMultipathIndicator();
+ method public double getPseudorangeRateMetersPerSecond();
+ method public double getPseudorangeRateUncertaintyMetersPerSecond();
+ method public long getReceivedSvTimeNanos();
+ method public long getReceivedSvTimeUncertaintyNanos();
method public double getSnrInDb();
- method public short getState();
- method public short getSvid();
- method public short getTimeFromLastBitInMs();
- method public double getTimeOffsetInNs();
- method public boolean hasAzimuthInDeg();
- method public boolean hasAzimuthUncertaintyInDeg();
- method public boolean hasBitNumber();
+ method public int getState();
+ method public int getSvid();
+ method public double getTimeOffsetNanos();
method public boolean hasCarrierCycles();
- method public boolean hasCarrierFrequencyInHz();
+ method public boolean hasCarrierFrequencyHz();
method public boolean hasCarrierPhase();
method public boolean hasCarrierPhaseUncertainty();
- method public boolean hasCodePhaseInChips();
- method public boolean hasCodePhaseUncertaintyInChips();
- method public boolean hasDopplerShiftInHz();
- method public boolean hasDopplerShiftUncertaintyInHz();
- method public boolean hasElevationInDeg();
- method public boolean hasElevationUncertaintyInDeg();
- method public boolean hasPseudorangeInMeters();
- method public boolean hasPseudorangeUncertaintyInMeters();
method public boolean hasSnrInDb();
- method public boolean hasTimeFromLastBitInMs();
method public boolean isPseudorangeRateCorrected();
- method public boolean isUsedInFix();
method public void reset();
- method public void resetAzimuthInDeg();
- method public void resetAzimuthUncertaintyInDeg();
- method public void resetBitNumber();
method public void resetCarrierCycles();
- method public void resetCarrierFrequencyInHz();
+ method public void resetCarrierFrequencyHz();
method public void resetCarrierPhase();
method public void resetCarrierPhaseUncertainty();
- method public void resetCodePhaseInChips();
- method public void resetCodePhaseUncertaintyInChips();
- method public void resetDopplerShiftInHz();
- method public void resetDopplerShiftUncertaintyInHz();
- method public void resetElevationInDeg();
- method public void resetElevationUncertaintyInDeg();
- method public void resetPseudorangeInMeters();
- method public void resetPseudorangeUncertaintyInMeters();
method public void resetSnrInDb();
- method public void resetTimeFromLastBitInMs();
method public void set(android.location.GnssMeasurement);
- method public void setAccumulatedDeltaRangeInMeters(double);
- method public void setAccumulatedDeltaRangeState(short);
- method public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
- method public void setAzimuthInDeg(double);
- method public void setAzimuthUncertaintyInDeg(double);
- method public void setBitNumber(int);
+ method public void setAccumulatedDeltaRangeMeters(double);
+ method public void setAccumulatedDeltaRangeState(int);
+ method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
method public void setCarrierCycles(long);
- method public void setCarrierFrequencyInHz(float);
+ method public void setCarrierFrequencyHz(float);
method public void setCarrierPhase(double);
method public void setCarrierPhaseUncertainty(double);
- method public void setCn0InDbHz(double);
- method public void setCodePhaseInChips(double);
- method public void setCodePhaseUncertaintyInChips(double);
- method public void setConstellationType(byte);
- method public void setDopplerShiftInHz(double);
- method public void setDopplerShiftUncertaintyInHz(double);
- method public void setElevationInDeg(double);
- method public void setElevationUncertaintyInDeg(double);
- method public void setLossOfLock(byte);
- method public void setMultipathIndicator(byte);
- method public void setPseudorangeInMeters(double);
- method public void setPseudorangeRateInMetersPerSec(double);
- method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
- method public void setPseudorangeUncertaintyInMeters(double);
- method public void setReceivedSvTimeInNs(long);
- method public void setReceivedSvTimeUncertaintyInNs(long);
+ method public void setCn0DbHz(double);
+ method public void setConstellationType(int);
+ method public void setMultipathIndicator(int);
+ method public void setPseudorangeRateMetersPerSecond(double);
+ method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
+ method public void setReceivedSvTimeNanos(long);
+ method public void setReceivedSvTimeUncertaintyNanos(long);
method public void setSnrInDb(double);
- method public void setState(short);
- method public void setSvid(short);
- method public void setTimeFromLastBitInMs(short);
- method public void setTimeOffsetInNs(double);
- method public void setUsedInFix(boolean);
+ method public void setState(int);
+ method public void setSvid(int);
+ method public void setTimeOffsetNanos(double);
method public void writeToParcel(android.os.Parcel, int);
- field public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
- field public static final short ADR_STATE_RESET = 2; // 0x2
- field public static final short ADR_STATE_UNKNOWN = 0; // 0x0
- field public static final short ADR_STATE_VALID = 1; // 0x1
+ field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
+ field public static final int ADR_STATE_RESET = 2; // 0x2
+ field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
+ field public static final int ADR_STATE_VALID = 1; // 0x1
field public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
- field public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
- field public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
- field public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
- field public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
- field public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
- field public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
- field public static final short STATE_BIT_SYNC = 2; // 0x2
- field public static final short STATE_CODE_LOCK = 1; // 0x1
- field public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
- field public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
- field public static final short STATE_TOW_DECODED = 8; // 0x8
- field public static final short STATE_UNKNOWN = 0; // 0x0
- }
-
- public static abstract class GnssMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
+ field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+ field public static final int MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
+ field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+ field public static final int STATE_BIT_SYNC = 2; // 0x2
+ field public static final int STATE_CODE_LOCK = 1; // 0x1
+ field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
+ field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
+ field public static final int STATE_TOW_DECODED = 8; // 0x8
+ field public static final int STATE_UNKNOWN = 0; // 0x0
}
public static abstract class GnssMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
@@ -19339,7 +19281,7 @@
method public java.util.Collection<android.location.GnssMeasurement> getMeasurements();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementsEvent> CREATOR;
- field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+ field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
field public static final int STATUS_READY = 1; // 0x1
}
@@ -19356,34 +19298,34 @@
public final class GnssNavigationMessage implements android.os.Parcelable {
method public int describeContents();
method public byte[] getData();
- method public short getMessageId();
- method public short getStatus();
- method public short getSubmessageId();
- method public short getSvid();
- method public short getType();
+ method public int getMessageId();
+ method public int getStatus();
+ method public int getSubmessageId();
+ method public int getSvid();
+ method public int getType();
method public void reset();
method public void set(android.location.GnssNavigationMessage);
method public void setData(byte[]);
- method public void setMessageId(short);
- method public void setStatus(short);
- method public void setSubmessageId(short);
- method public void setSvid(short);
- method public void setType(short);
+ method public void setMessageId(int);
+ method public void setStatus(int);
+ method public void setSubmessageId(int);
+ method public void setSvid(int);
+ method public void setType(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
- field public static final short MESSAGE_TYPE_BDS_D1 = 1281; // 0x501
- field public static final short MESSAGE_TYPE_BDS_D2 = 1282; // 0x502
- field public static final short MESSAGE_TYPE_GAL_F = 1538; // 0x602
- field public static final short MESSAGE_TYPE_GAL_I = 1537; // 0x601
- field public static final short MESSAGE_TYPE_GLO_L1CA = 769; // 0x301
- field public static final short MESSAGE_TYPE_GPS_CNAV2 = 260; // 0x104
- field public static final short MESSAGE_TYPE_GPS_L1CA = 257; // 0x101
- field public static final short MESSAGE_TYPE_GPS_L2CNAV = 258; // 0x102
- field public static final short MESSAGE_TYPE_GPS_L5CNAV = 259; // 0x103
- field public static final short MESSAGE_TYPE_UNKNOWN = 0; // 0x0
- field public static final short STATUS_PARITY_PASSED = 1; // 0x1
- field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
- field public static final short STATUS_UNKNOWN = 0; // 0x0
+ field public static final int STATUS_PARITY_PASSED = 1; // 0x1
+ field public static final int STATUS_PARITY_REBUILT = 2; // 0x2
+ field public static final int STATUS_UNKNOWN = 0; // 0x0
+ field public static final int TYPE_BDS_D1 = 1281; // 0x501
+ field public static final int TYPE_BDS_D2 = 1282; // 0x502
+ field public static final int TYPE_GAL_F = 1538; // 0x602
+ field public static final int TYPE_GAL_I = 1537; // 0x601
+ field public static final int TYPE_GLO_L1CA = 769; // 0x301
+ field public static final int TYPE_GPS_CNAV2 = 260; // 0x104
+ field public static final int TYPE_GPS_L1CA = 257; // 0x101
+ field public static final int TYPE_GPS_L2CNAV = 258; // 0x102
+ field public static final int TYPE_GPS_L5CNAV = 259; // 0x103
+ field public static final int TYPE_UNKNOWN = 0; // 0x0
}
public static abstract class GnssNavigationMessage.GnssNavigationMessageType implements java.lang.annotation.Annotation {
@@ -19395,7 +19337,7 @@
method public android.location.GnssNavigationMessage getNavigationMessage();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessageEvent> CREATOR;
- field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+ field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
field public static final int STATUS_READY = 1; // 0x1
}
@@ -19414,22 +19356,22 @@
}
public final class GnssStatus {
- method public float getAzimuth(int);
- method public byte getConstellationType(int);
- method public float getElevation(int);
+ method public float getAzimuthDegrees(int);
+ method public float getCn0DbHz(int);
+ method public int getConstellationType(int);
+ method public float getElevationDegrees(int);
method public int getNumSatellites();
- method public float getSnr(int);
method public int getSvid(int);
method public boolean hasAlmanac(int);
method public boolean hasEphemeris(int);
method public boolean usedInFix(int);
- field public static final byte CONSTELLATION_BEIDOU = 5; // 0x5
- field public static final byte CONSTELLATION_GALILEO = 6; // 0x6
- field public static final byte CONSTELLATION_GLONASS = 3; // 0x3
- field public static final byte CONSTELLATION_GPS = 1; // 0x1
- field public static final byte CONSTELLATION_QZSS = 4; // 0x4
- field public static final byte CONSTELLATION_SBAS = 2; // 0x2
- field public static final byte CONSTELLATION_UNKNOWN = 0; // 0x0
+ field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final int CONSTELLATION_GPS = 1; // 0x1
+ field public static final int CONSTELLATION_QZSS = 4; // 0x4
+ field public static final int CONSTELLATION_SBAS = 2; // 0x2
+ field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
}
public static abstract class GnssStatus.ConstellationType implements java.lang.annotation.Annotation {
@@ -19545,8 +19487,8 @@
method public java.util.List<java.lang.String> getProviders(boolean);
method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
method public boolean isProviderEnabled(java.lang.String);
- method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
- method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
+ method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
+ method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback, android.os.Handler);
method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
@@ -19571,7 +19513,7 @@
method public void setTestProviderEnabled(java.lang.String, boolean);
method public void setTestProviderLocation(java.lang.String, android.location.Location);
method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
- method public void unregisterGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
+ method public void unregisterGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
method public void unregisterGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
method public void unregisterGnssStatusCallback(android.location.GnssStatusCallback);
field public static final java.lang.String GPS_PROVIDER = "gps";
@@ -19935,7 +19877,7 @@
public static abstract class AudioManager.AudioRecordingCallback {
ctor public AudioManager.AudioRecordingCallback();
- method public void onRecordConfigChanged();
+ method public void onRecordConfigChanged(android.media.AudioRecordConfiguration[]);
}
public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -21003,6 +20945,7 @@
field public static final java.lang.String KEY_SLICE_HEIGHT = "slice-height";
field public static final java.lang.String KEY_STRIDE = "stride";
field public static final java.lang.String KEY_TEMPORAL_LAYERING = "ts-schema";
+ field public static final java.lang.String KEY_TRACK_ID = "track-id";
field public static final java.lang.String KEY_WIDTH = "width";
field public static final java.lang.String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
field public static final java.lang.String MIMETYPE_AUDIO_AC3 = "audio/ac3";
@@ -29115,6 +29058,8 @@
ctor public Process();
method public static final long getElapsedCpuTime();
method public static final int getGidForName(java.lang.String);
+ method public static final long getStartElapsedRealtime();
+ method public static final long getStartUptimeMillis();
method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
method public static final int getUidForName(java.lang.String);
method public static final boolean is64Bit();
@@ -31784,6 +31729,7 @@
public static final class DocumentsContract.Root {
field public static final java.lang.String COLUMN_AVAILABLE_BYTES = "available_bytes";
+ field public static final java.lang.String COLUMN_CAPACITY_BYTES = "capacity_bytes";
field public static final java.lang.String COLUMN_DOCUMENT_ID = "document_id";
field public static final java.lang.String COLUMN_FLAGS = "flags";
field public static final java.lang.String COLUMN_ICON = "icon";
@@ -34308,7 +34254,8 @@
ctor public CarrierMessagingService();
method public android.os.IBinder onBind(android.content.Intent);
method public void onDownloadMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
- method public void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+ method public deprecated void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+ method public void onReceiveTextSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
method public deprecated void onSendDataSms(byte[], int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
method public void onSendDataSms(byte[], int, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
method public void onSendMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMmsResult>);
@@ -34319,6 +34266,9 @@
field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2
field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0
field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
+ field public static final int RECEIVE_OPTIONS_DEFAULT = 0; // 0x0
+ field public static final int RECEIVE_OPTIONS_DROP = 1; // 0x1
+ field public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE = 2; // 0x2
field public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1; // 0x1
field public static final int SEND_STATUS_ERROR = 2; // 0x2
field public static final int SEND_STATUS_OK = 0; // 0x0
@@ -38547,7 +38497,6 @@
method public boolean hasNext();
method public java.util.Iterator<java.lang.String> iterator();
method public java.lang.String next();
- method public void remove();
method public void setString(java.lang.String);
}
@@ -40159,6 +40108,7 @@
method public int describeContents();
method public static android.util.LocaleList forLanguageTags(java.lang.String);
method public java.util.Locale get(int);
+ method public static android.util.LocaleList getAdjustedDefault();
method public static android.util.LocaleList getDefault();
method public static android.util.LocaleList getEmptyLocaleList();
method public java.util.Locale getFirstMatch(java.lang.String[]);
@@ -57782,9 +57732,10 @@
}
public abstract interface Iterator {
+ method public default void forEachRemaining(java.util.function.Consumer<? super E>);
method public abstract boolean hasNext();
method public abstract E next();
- method public abstract void remove();
+ method public default void remove();
}
public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
@@ -58087,6 +58038,79 @@
method public abstract void update(java.util.Observable, java.lang.Object);
}
+ public final class Optional {
+ method public static java.util.Optional<T> empty();
+ method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
+ method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
+ method public T get();
+ method public void ifPresent(java.util.function.Consumer<? super T>);
+ method public boolean isPresent();
+ method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
+ method public static java.util.Optional<T> of(T);
+ method public static java.util.Optional<T> ofNullable(T);
+ method public T orElse(T);
+ method public T orElseGet(java.util.function.Supplier<? extends T>);
+ method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
+ }
+
+ public final class OptionalDouble {
+ method public static java.util.OptionalDouble empty();
+ method public double getAsDouble();
+ method public void ifPresent(java.util.function.DoubleConsumer);
+ method public boolean isPresent();
+ method public static java.util.OptionalDouble of(double);
+ method public double orElse(double);
+ method public double orElseGet(java.util.function.DoubleSupplier);
+ method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+ }
+
+ public final class OptionalInt {
+ method public static java.util.OptionalInt empty();
+ method public int getAsInt();
+ method public void ifPresent(java.util.function.IntConsumer);
+ method public boolean isPresent();
+ method public static java.util.OptionalInt of(int);
+ method public int orElse(int);
+ method public int orElseGet(java.util.function.IntSupplier);
+ method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+ }
+
+ public final class OptionalLong {
+ method public static java.util.OptionalLong empty();
+ method public long getAsLong();
+ method public void ifPresent(java.util.function.LongConsumer);
+ method public boolean isPresent();
+ method public static java.util.OptionalLong of(long);
+ method public long orElse(long);
+ method public long orElseGet(java.util.function.LongSupplier);
+ method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+ }
+
+ public abstract interface PrimitiveIterator implements java.util.Iterator {
+ method public abstract void forEachRemaining(T_CONS);
+ }
+
+ public static abstract interface PrimitiveIterator.OfDouble implements java.util.PrimitiveIterator {
+ method public default void forEachRemaining(java.util.function.DoubleConsumer);
+ method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Double>);
+ method public default java.lang.Double next();
+ method public abstract double nextDouble();
+ }
+
+ public static abstract interface PrimitiveIterator.OfInt implements java.util.PrimitiveIterator {
+ method public default void forEachRemaining(java.util.function.IntConsumer);
+ method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Integer>);
+ method public default java.lang.Integer next();
+ method public abstract int nextInt();
+ }
+
+ public static abstract interface PrimitiveIterator.OfLong implements java.util.PrimitiveIterator {
+ method public default void forEachRemaining(java.util.function.LongConsumer);
+ method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Long>);
+ method public default java.lang.Long next();
+ method public abstract long nextLong();
+ }
+
public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
ctor public PriorityQueue();
ctor public PriorityQueue(int);
@@ -58258,7 +58282,6 @@
method public short nextShort();
method public short nextShort(int);
method public int radix();
- method public void remove();
method public java.util.Scanner reset();
method public java.util.Scanner skip(java.util.regex.Pattern);
method public java.util.Scanner skip(java.lang.String);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index df0e5fc..fea6f0e 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -606,7 +606,7 @@
new File(mProfileFile),
ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE |
- ParcelFileDescriptor.MODE_READ_WRITE);
+ ParcelFileDescriptor.MODE_WRITE_ONLY);
} catch (FileNotFoundException e) {
System.err.println("Error: Unable to open file: " + mProfileFile);
System.err.println("Consider using a file under /data/local/tmp/");
@@ -903,7 +903,7 @@
fd = openForSystemServer(file,
ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE |
- ParcelFileDescriptor.MODE_READ_WRITE);
+ ParcelFileDescriptor.MODE_WRITE_ONLY);
} catch (FileNotFoundException e) {
System.err.println("Error: Unable to open file: " + filename);
System.err.println("Consider using a file under /data/local/tmp/");
@@ -992,7 +992,7 @@
new File(profileFile),
ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE |
- ParcelFileDescriptor.MODE_READ_WRITE);
+ ParcelFileDescriptor.MODE_WRITE_ONLY);
} catch (FileNotFoundException e) {
System.err.println("Error: Unable to open file: " + profileFile);
System.err.println("Consider using a file under /data/local/tmp/");
@@ -1052,7 +1052,7 @@
fd = openForSystemServer(file,
ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE |
- ParcelFileDescriptor.MODE_READ_WRITE);
+ ParcelFileDescriptor.MODE_WRITE_ONLY);
} catch (FileNotFoundException e) {
System.err.println("Error: Unable to open file: " + heapFile);
System.err.println("Consider using a file under /data/local/tmp/");
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 20d71a6..8d03b55 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -108,7 +108,7 @@
float pathErrorScale) throws NotFoundException {
final ConfigurationBoundResourceCache<Animator> animatorCache = resources
.getAnimatorCache();
- Animator animator = animatorCache.getInstance(id, theme);
+ Animator animator = animatorCache.getInstance(id, resources, theme);
if (animator != null) {
if (DBG_ANIMATOR_INFLATER) {
Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id));
@@ -157,7 +157,7 @@
final ConfigurationBoundResourceCache<StateListAnimator> cache = resources
.getStateListAnimatorCache();
final Theme theme = context.getTheme();
- StateListAnimator animator = cache.getInstance(id, theme);
+ StateListAnimator animator = cache.getInstance(id, resources, theme);
if (animator != null) {
return animator;
}
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index e721de9..5ab2c1d 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1029,8 +1029,16 @@
@Override
public void resume() {
- if (mPaused) {
+ if (Looper.myLooper() == null) {
+ throw new AndroidRuntimeException("Animators may only be resumed from the same " +
+ "thread that the animator was started on");
+ }
+ if (mPaused && !mResumed) {
mResumed = true;
+ if (mPauseTime > 0) {
+ AnimationHandler handler = AnimationHandler.getInstance();
+ handler.addAnimationFrameCallback(this, 0);
+ }
}
super.resume();
}
@@ -1235,9 +1243,8 @@
}
mLastFrameTime = frameTime;
if (mPaused) {
- if (mPauseTime < 0) {
- mPauseTime = frameTime;
- }
+ mPauseTime = frameTime;
+ handler.removeCallback(this);
return;
} else if (mResumed) {
mResumed = false;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index be89b20..b87e9fa2 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6599,7 +6599,8 @@
if (isAppDebuggable || isDlwarningEnabled) {
String dlwarning = getDlWarning();
if (dlwarning != null) {
- String appName = getString(mApplication.getApplicationInfo().labelRes);
+ String appName = getApplicationInfo().loadLabel(getPackageManager())
+ .toString();
String warning = "Detected problems with app native libraries\n" +
"(please consult log for detail):\n" + dlwarning;
if (isAppDebuggable) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 4aab163..a4e5b90 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -577,6 +577,16 @@
}
/**
+ * Return whether a stackId is a stack containing floating windows. Floating windows
+ * are laid out differently as they are allowed to extend past the display bounds
+ * without overscan insets.
+ */
+ public static boolean tasksAreFloating(int stackId) {
+ return stackId == FREEFORM_WORKSPACE_STACK_ID
+ || stackId == PINNED_STACK_ID;
+ }
+
+ /**
* Returns true if animation specs should be constructed for app transition that moves
* the task to the specified stack.
*/
@@ -647,6 +657,16 @@
return stackId != PINNED_STACK_ID && stackId != FREEFORM_WORKSPACE_STACK_ID
&& stackId != DOCKED_STACK_ID;
}
+
+ /**
+ * Returns true if the input stack id should only be present on a device that supports
+ * multi-window mode.
+ * @see android.app.ActivityManager#supportsMultiWindow
+ */
+ public static boolean isMultiWindowStack(int stackId) {
+ return isStaticStack(stackId) || stackId == PINNED_STACK_ID
+ || stackId == FREEFORM_WORKSPACE_STACK_ID || stackId == DOCKED_STACK_ID;
+ }
}
/**
@@ -868,6 +888,17 @@
}
/**
+ * Returns true if the system supports at least one form of multi-window.
+ * E.g. freeform, split-screen, picture-in-picture.
+ * @hide
+ */
+ static public boolean supportsMultiWindow() {
+ return !isLowRamDeviceStatic()
+ && Resources.getSystem().getBoolean(
+ com.android.internal.R.bool.config_supportsMultiWindow);
+ }
+
+ /**
* Information you can set and retrieve about the current activity within the recent task list.
*/
public static class TaskDescription implements Parcelable {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 9d8dca60..ff7f70d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -823,7 +823,21 @@
reply.writeNoException();
return true;
}
-
+ case RESIZE_PINNED_STACK_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final boolean hasBounds = data.readInt() != 0;
+ Rect bounds = null;
+ if (hasBounds) {
+ bounds = Rect.CREATOR.createFromParcel(data);
+ }
+ final boolean hasTempPinnedTaskBounds = data.readInt() != 0;
+ Rect tempPinnedTaskBounds = null;
+ if (hasTempPinnedTaskBounds) {
+ tempPinnedTaskBounds = Rect.CREATOR.createFromParcel(data);
+ }
+ resizePinnedStack(bounds, tempPinnedTaskBounds);
+ return true;
+ }
case RESIZE_DOCKED_STACK_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
final boolean hasBounds = data.readInt() != 0;
@@ -3914,6 +3928,31 @@
data.recycle();
reply.recycle();
}
+
+ @Override
+ public void resizePinnedStack(Rect pinnedBounds, Rect tempPinnedTaskBounds) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ if (pinnedBounds != null) {
+ data.writeInt(1);
+ pinnedBounds.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ if (tempPinnedTaskBounds != null) {
+ data.writeInt(1);
+ tempPinnedTaskBounds.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ mRemote.transact(RESIZE_PINNED_STACK_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
@Override
public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException
{
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1e95c98..1bc33b8 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1788,7 +1788,8 @@
}
/**
- * Creates the top level resources for the given package.
+ * Creates the top level resources for the given package. Will return an existing
+ * Resources if one has already been created.
*/
Resources getTopLevelResources(String resDir, String[] splitResDirs, String[] overlayDirs,
String[] libDirs, int displayId, Configuration overrideConfiguration,
@@ -1798,6 +1799,19 @@
pkgInfo.getClassLoader());
}
+ /**
+ * Creates a new top level resources for the given package. Will always create a new
+ * Resources, regardless if one has already been created.
+ */
+ Resources getNewTopLevelResources(String resDir, String[] splitResDirs, String[] overlayDirs,
+ String[] libDirs, int displayId, Configuration overrideConfiguration,
+ LoadedApk pkgInfo) {
+ mResourcesManager.removeTopLevelResources(
+ resDir, displayId, overrideConfiguration, pkgInfo.getCompatibilityInfo());
+ return getTopLevelResources(resDir, splitResDirs, overlayDirs, libDirs,
+ displayId, overrideConfiguration, pkgInfo);
+ }
+
final Handler getHandler() {
return mH;
}
@@ -4749,29 +4763,87 @@
final void handleDispatchPackageBroadcast(int cmd, String[] packages) {
boolean hasPkgInfo = false;
- if (packages != null) {
- synchronized (mResourcesManager) {
- for (int i=packages.length-1; i>=0; i--) {
- //Slog.i(TAG, "Cleaning old package: " + packages[i]);
- if (!hasPkgInfo) {
- WeakReference<LoadedApk> ref;
- ref = mPackages.get(packages[i]);
- if (ref != null && ref.get() != null) {
+ switch (cmd) {
+ case IApplicationThread.PACKAGE_REMOVED:
+ case IApplicationThread.PACKAGE_REMOVED_DONT_KILL:
+ {
+ final boolean killApp = cmd == IApplicationThread.PACKAGE_REMOVED;
+ if (packages == null) {
+ break;
+ }
+ synchronized (mResourcesManager) {
+ for (int i = packages.length - 1; i >= 0; i--) {
+ if (!hasPkgInfo) {
+ WeakReference<LoadedApk> ref = mPackages.get(packages[i]);
+ if (ref != null && ref.get() != null) {
+ hasPkgInfo = true;
+ } else {
+ ref = mResourcePackages.get(packages[i]);
+ if (ref != null && ref.get() != null) {
+ hasPkgInfo = true;
+ }
+ }
+ }
+ if (killApp) {
+ mPackages.remove(packages[i]);
+ mResourcePackages.remove(packages[i]);
+ }
+ }
+ }
+ break;
+ }
+ case IApplicationThread.PACKAGE_REPLACED:
+ {
+ if (packages == null) {
+ break;
+ }
+ synchronized (mResourcesManager) {
+ for (int i = packages.length - 1; i >= 0; i--) {
+ WeakReference<LoadedApk> ref = mPackages.get(packages[i]);
+ LoadedApk pkgInfo = ref != null ? ref.get() : null;
+ if (pkgInfo != null) {
hasPkgInfo = true;
} else {
ref = mResourcePackages.get(packages[i]);
- if (ref != null && ref.get() != null) {
+ pkgInfo = ref != null ? ref.get() : null;
+ if (pkgInfo != null) {
hasPkgInfo = true;
}
}
+ // If the package is being replaced, yet it still has a valid
+ // LoadedApk object, the package was updated with _DONT_KILL.
+ // Adjust it's internal references to the application info and
+ // resources.
+ if (pkgInfo != null) {
+ try {
+ final String packageName = packages[i];
+ final ApplicationInfo aInfo =
+ sPackageManager.getApplicationInfo(
+ packageName,
+ 0 /*flags*/,
+ UserHandle.myUserId());
+
+ if (mActivities.size() > 0) {
+ for (ActivityClientRecord ar : mActivities.values()) {
+ if (ar.activityInfo.applicationInfo.packageName
+ .equals(packageName)) {
+ ar.activityInfo.applicationInfo = aInfo;
+ ar.packageInfo = pkgInfo;
+ }
+ }
+ }
+ final List<String> oldPaths =
+ sPackageManager.getPreviousCodePaths(packageName);
+ pkgInfo.updateApplicationInfo(aInfo, oldPaths);
+ } catch (RemoteException e) {
+ }
+ }
}
- mPackages.remove(packages[i]);
- mResourcePackages.remove(packages[i]);
}
+ break;
}
}
- ApplicationPackageManager.handlePackageBroadcast(cmd, packages,
- hasPkgInfo);
+ ApplicationPackageManager.handlePackageBroadcast(cmd, packages, hasPkgInfo);
}
final void handleLowMemory() {
@@ -4909,6 +4981,9 @@
DdmVmInternal.enableRecentAllocations(true);
}
+ // Note when this process has started.
+ Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
+
mBoundApplication = data;
mConfiguration = new Configuration(data.config);
mCompatConfiguration = new Configuration(data.config);
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
index b20c091..0fc097e 100644
--- a/core/java/android/app/ApplicationLoaders.java
+++ b/core/java/android/app/ApplicationLoaders.java
@@ -86,6 +86,18 @@
String libraryPermittedPath,
boolean isShared);
+ /**
+ * Adds a new path the classpath of the given loader.
+ * @throws IllegalStateException if the provided class loader is not a {@link PathClassLoader}.
+ */
+ void addPath(ClassLoader classLoader, String dexPath) {
+ if (!(classLoader instanceof PathClassLoader)) {
+ throw new IllegalStateException("class loader is not a PathClassLoader");
+ }
+ final PathClassLoader baseDexClassLoader = (PathClassLoader) classLoader;
+ baseDexClassLoader.addDexPath(dexPath);
+ }
+
private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<String, ClassLoader>();
private static final ApplicationLoaders gApplicationLoaders
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 53cc9ca..38f32f7 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1093,6 +1093,14 @@
}
@Override
+ public Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
+ int badgeDensity) {
+ Drawable badgeDrawable = getDrawableForDensity(
+ com.android.internal.R.drawable.ic_corp_badge, badgeDensity);
+ return getBadgedDrawable(drawable, badgeDrawable, badgeLocation, true);
+ }
+
+ @Override
public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
final int badgeResId = getBadgeResIdForUser(user.getIdentifier());
if (badgeResId == 0) {
@@ -1114,24 +1122,27 @@
@Override
public Drawable getUserBadgeForDensity(UserHandle user, int density) {
- return getManagedProfileIconForDensity(user, density,
- com.android.internal.R.drawable.ic_corp_badge);
+ return getManagedProfileIconForDensity(user, com.android.internal.R.drawable.ic_corp_badge,
+ density);
}
@Override
public Drawable getUserBadgeForDensityNoBackground(UserHandle user, int density) {
- return getManagedProfileIconForDensity(user, density,
- com.android.internal.R.drawable.ic_corp_badge_no_background);
+ return getManagedProfileIconForDensity(user,
+ com.android.internal.R.drawable.ic_corp_badge_no_background, density);
}
- private Drawable getManagedProfileIconForDensity(UserHandle user, int density,
- int drawableId) {
+ private Drawable getDrawableForDensity(int drawableId, int density) {
+ if (density <= 0) {
+ density = mContext.getResources().getDisplayMetrics().densityDpi;
+ }
+ return Resources.getSystem().getDrawableForDensity(drawableId, density);
+ }
+
+ private Drawable getManagedProfileIconForDensity(UserHandle user, int drawableId, int density) {
UserInfo userInfo = getUserIfProfile(user.getIdentifier());
if (userInfo != null && userInfo.isManagedProfile()) {
- if (density <= 0) {
- density = mContext.getResources().getDisplayMetrics().densityDpi;
- }
- return Resources.getSystem().getDrawableForDensity(drawableId, density);
+ return getDrawableForDensity(drawableId, density);
}
return null;
}
@@ -1532,9 +1543,9 @@
}
@Override
- public void verifyIntentFilter(int id, int verificationCode, List<String> outFailedDomains) {
+ public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) {
try {
- mPM.verifyIntentFilter(id, verificationCode, outFailedDomains);
+ mPM.verifyIntentFilter(id, verificationCode, failedDomains);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index d78f59f..70bff80 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -171,6 +171,16 @@
public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
Rect tempDockedTaskInsetBounds,
Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) throws RemoteException;
+ /**
+ * Resizes the pinned stack.
+ *
+ * @param pinnedBounds The bounds for the pinned stack.
+ * @param tempPinnedTaskBounds The temporary bounds for the tasks in the pinned stack, which
+ * might be different from the stack bounds to allow more
+ * flexibility while resizing, or {@code null} if they should be the
+ * same as the stack bounds.
+ */
+ public void resizePinnedStack(Rect pinnedBounds, Rect tempPinnedTaskBounds) throws RemoteException;
public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException;
public List<StackInfo> getAllStackInfos() throws RemoteException;
public StackInfo getStackInfo(int stackId) throws RemoteException;
@@ -982,4 +992,5 @@
int REMOVE_STACK = IBinder.FIRST_CALL_TRANSACTION + 367;
int SET_LENIENT_BACKGROUND_CHECK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+368;
int GET_MEMORY_TRIM_LEVEL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+369;
+ int RESIZE_PINNED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 370;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index a3c9591..628bde0 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -123,8 +123,13 @@
void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd)
throws RemoteException;
void setSchedulingGroup(int group) throws RemoteException;
+ // the package has been removed, clean up internal references
static final int PACKAGE_REMOVED = 0;
static final int EXTERNAL_STORAGE_UNAVAILABLE = 1;
+ // the package is being modified in-place, don't kill it and retain references to it
+ static final int PACKAGE_REMOVED_DONT_KILL = 2;
+ // a previously removed package was replaced with a new version [eg. upgrade, split added, ...]
+ static final int PACKAGE_REPLACED = 3;
void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException;
void scheduleCrash(String msg) throws RemoteException;
void dumpActivity(FileDescriptor fd, IBinder servicetoken, String prefix, String[] args)
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index b65faa9..cd17078 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -58,6 +58,7 @@
import java.net.URL;
import java.util.List;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Objects;
@@ -83,24 +84,25 @@
private static final String TAG = "LoadedApk";
private final ActivityThread mActivityThread;
- private ApplicationInfo mApplicationInfo;
final String mPackageName;
- private final String mAppDir;
- private final String mResDir;
- private final String[] mSplitAppDirs;
- private final String[] mSplitResDirs;
- private final String[] mOverlayDirs;
- private final String[] mSharedLibraries;
- private final String mDataDir;
- private final String mLibDir;
- private final File mDataDirFile;
- private final File mDeviceEncryptedDataDirFile;
- private final File mCredentialEncryptedDataDirFile;
+ private ApplicationInfo mApplicationInfo;
+ private String mAppDir;
+ private String mResDir;
+ private String[] mSplitAppDirs;
+ private String[] mSplitResDirs;
+ private String[] mOverlayDirs;
+ private String[] mSharedLibraries;
+ private String mDataDir;
+ private String mLibDir;
+ private File mDataDirFile;
+ private File mDeviceEncryptedDataDirFile;
+ private File mCredentialEncryptedDataDirFile;
private final ClassLoader mBaseClassLoader;
private final boolean mSecurityViolation;
private final boolean mIncludeCode;
private final boolean mRegisterPackage;
private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
+ /** WARNING: This may change. Don't hold external references to it. */
Resources mResources;
private ClassLoader mClassLoader;
private Application mApplication;
@@ -129,23 +131,10 @@
public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
CompatibilityInfo compatInfo, ClassLoader baseLoader,
boolean securityViolation, boolean includeCode, boolean registerPackage) {
- final int myUid = Process.myUid();
- aInfo = adjustNativeLibraryPaths(aInfo);
mActivityThread = activityThread;
- mApplicationInfo = aInfo;
+ setApplicationInfo(aInfo);
mPackageName = aInfo.packageName;
- mAppDir = aInfo.sourceDir;
- mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir;
- mSplitAppDirs = aInfo.splitSourceDirs;
- mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs;
- mOverlayDirs = aInfo.resourceDirs;
- mSharedLibraries = aInfo.sharedLibraryFiles;
- mDataDir = aInfo.dataDir;
- mDataDirFile = FileUtils.newFileOrNull(mDataDir);
- mDeviceEncryptedDataDirFile = FileUtils.newFileOrNull(aInfo.deviceEncryptedDataDir);
- mCredentialEncryptedDataDirFile = FileUtils.newFileOrNull(aInfo.credentialEncryptedDataDir);
- mLibDir = aInfo.nativeLibraryDir;
mBaseClassLoader = baseLoader;
mSecurityViolation = securityViolation;
mIncludeCode = includeCode;
@@ -266,26 +255,165 @@
return ai.sharedLibraryFiles;
}
- public ClassLoader getClassLoader() {
- synchronized (this) {
- if (mClassLoader != null) {
- return mClassLoader;
- }
+ public void updateApplicationInfo(ApplicationInfo aInfo, List<String> oldPaths) {
+ setApplicationInfo(aInfo);
- if (mPackageName.equals("android")) {
- if (mBaseClassLoader == null) {
- mClassLoader = ClassLoader.getSystemClassLoader();
- } else {
- mClassLoader = mBaseClassLoader;
+ final List<String> newPaths = new ArrayList<>();
+ makePaths(mActivityThread, aInfo, newPaths, null /*libPaths*/);
+ final List<String> addedPaths = new ArrayList<>(newPaths.size());
+
+ if (oldPaths != null) {
+ for (String path : newPaths) {
+ final String apkName = path.substring(path.lastIndexOf(File.separator));
+ boolean match = false;
+ for (String oldPath : oldPaths) {
+ final String oldApkName = oldPath.substring(path.lastIndexOf(File.separator));
+ if (apkName.equals(oldApkName)) {
+ match = true;
+ break;
+ }
}
- return mClassLoader;
+ if (!match) {
+ addedPaths.add(path);
+ }
+ }
+ } else {
+ addedPaths.addAll(newPaths);
+ }
+ synchronized (this) {
+ mClassLoader = createOrUpdateClassLoaderLocked(addedPaths);
+ if (mResources != null) {
+ mResources = mActivityThread.getNewTopLevelResources(mResDir, mSplitResDirs,
+ mOverlayDirs, mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY,
+ null /*overrideConfiguration*/, this);
+ }
+ }
+ }
+
+ private void setApplicationInfo(ApplicationInfo aInfo) {
+ final int myUid = Process.myUid();
+ aInfo = adjustNativeLibraryPaths(aInfo);
+ mApplicationInfo = aInfo;
+ mAppDir = aInfo.sourceDir;
+ mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir;
+ mSplitAppDirs = aInfo.splitSourceDirs;
+ mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs;
+ mOverlayDirs = aInfo.resourceDirs;
+ mSharedLibraries = aInfo.sharedLibraryFiles;
+ mDataDir = aInfo.dataDir;
+ mLibDir = aInfo.nativeLibraryDir;
+ mDataDirFile = FileUtils.newFileOrNull(aInfo.dataDir);
+ mDeviceEncryptedDataDirFile = FileUtils.newFileOrNull(aInfo.deviceEncryptedDataDir);
+ mCredentialEncryptedDataDirFile = FileUtils.newFileOrNull(aInfo.credentialEncryptedDataDir);
+ }
+
+ public static void makePaths(ActivityThread activityThread, ApplicationInfo aInfo,
+ List<String> outZipPaths, List<String> outLibPaths) {
+ final String appDir = aInfo.sourceDir;
+ final String[] splitAppDirs = aInfo.splitSourceDirs;
+ final String libDir = aInfo.nativeLibraryDir;
+ final String[] sharedLibraries = aInfo.sharedLibraryFiles;
+
+ outZipPaths.clear();
+ outZipPaths.add(appDir);
+ if (splitAppDirs != null) {
+ Collections.addAll(outZipPaths, splitAppDirs);
+ }
+
+ if (outLibPaths != null) {
+ outLibPaths.clear();
+ }
+
+ /*
+ * The following is a bit of a hack to inject
+ * instrumentation into the system: If the app
+ * being started matches one of the instrumentation names,
+ * then we combine both the "instrumentation" and
+ * "instrumented" app into the path, along with the
+ * concatenation of both apps' shared library lists.
+ */
+
+ String instrumentationPackageName = activityThread.mInstrumentationPackageName;
+ String instrumentationAppDir = activityThread.mInstrumentationAppDir;
+ String[] instrumentationSplitAppDirs = activityThread.mInstrumentationSplitAppDirs;
+ String instrumentationLibDir = activityThread.mInstrumentationLibDir;
+
+ String instrumentedAppDir = activityThread.mInstrumentedAppDir;
+ String[] instrumentedSplitAppDirs = activityThread.mInstrumentedSplitAppDirs;
+ String instrumentedLibDir = activityThread.mInstrumentedLibDir;
+ String[] instrumentationLibs = null;
+
+ if (appDir.equals(instrumentationAppDir)
+ || appDir.equals(instrumentedAppDir)) {
+ outZipPaths.clear();
+ outZipPaths.add(instrumentationAppDir);
+ if (instrumentationSplitAppDirs != null) {
+ Collections.addAll(outZipPaths, instrumentationSplitAppDirs);
+ }
+ outZipPaths.add(instrumentedAppDir);
+ if (instrumentedSplitAppDirs != null) {
+ Collections.addAll(outZipPaths, instrumentedSplitAppDirs);
}
+ if (outLibPaths != null) {
+ outLibPaths.add(instrumentationLibDir);
+ outLibPaths.add(instrumentedLibDir);
+ }
+
+ if (!instrumentedAppDir.equals(instrumentationAppDir)) {
+ instrumentationLibs = getLibrariesFor(instrumentationPackageName);
+ }
+ }
+
+ if (outLibPaths != null) {
+ if (outLibPaths.isEmpty()) {
+ outLibPaths.add(libDir);
+ }
+
+ // Add path to libraries in apk for current abi. Do this now because more entries
+ // will be added to zipPaths that shouldn't be part of the library path.
+ if (aInfo.primaryCpuAbi != null) {
+ for (String apk : outZipPaths) {
+ outLibPaths.add(apk + "!/lib/" + aInfo.primaryCpuAbi);
+ }
+ }
+
+ if (aInfo.isSystemApp() && !aInfo.isUpdatedSystemApp()) {
+ // Add path to system libraries to libPaths;
+ // Access to system libs should be limited
+ // to bundled applications; this is why updated
+ // system apps are not included.
+ outLibPaths.add(System.getProperty("java.library.path"));
+ }
+ }
+
+ if (sharedLibraries != null) {
+ for (String lib : sharedLibraries) {
+ if (!outZipPaths.contains(lib)) {
+ outZipPaths.add(0, lib);
+ }
+ }
+ }
+
+ if (instrumentationLibs != null) {
+ for (String lib : instrumentationLibs) {
+ if (!outZipPaths.contains(lib)) {
+ outZipPaths.add(0, lib);
+ }
+ }
+ }
+
+ final String zip = TextUtils.join(File.pathSeparator, outZipPaths);
+ }
+
+ private ClassLoader createOrUpdateClassLoaderLocked(List<String> addedPaths) {
+ final ClassLoader classLoader;
+ if (mIncludeCode && !mPackageName.equals("android")) {
// Avoid the binder call when the package is the current application package.
// The activity manager will perform ensure that dexopt is performed before
// spinning up the process.
if (!Objects.equals(mPackageName, ActivityThread.currentPackageName())) {
- final String isa = VMRuntime.getRuntime().vmInstructionSet();
+ VMRuntime.getRuntime().vmInstructionSet();
try {
ActivityThread.getPackageManager().notifyPackageUse(mPackageName);
} catch (RemoteException re) {
@@ -294,7 +422,6 @@
}
final List<String> zipPaths = new ArrayList<>();
- final List<String> apkPaths = new ArrayList<>();
final List<String> libPaths = new ArrayList<>();
if (mRegisterPackage) {
@@ -305,91 +432,12 @@
}
}
- zipPaths.add(mAppDir);
- if (mSplitAppDirs != null) {
- Collections.addAll(zipPaths, mSplitAppDirs);
- }
-
- libPaths.add(mLibDir);
-
- /*
- * The following is a bit of a hack to inject
- * instrumentation into the system: If the app
- * being started matches one of the instrumentation names,
- * then we combine both the "instrumentation" and
- * "instrumented" app into the path, along with the
- * concatenation of both apps' shared library lists.
- */
-
- String instrumentationPackageName = mActivityThread.mInstrumentationPackageName;
- String instrumentationAppDir = mActivityThread.mInstrumentationAppDir;
- String[] instrumentationSplitAppDirs = mActivityThread.mInstrumentationSplitAppDirs;
- String instrumentationLibDir = mActivityThread.mInstrumentationLibDir;
-
- String instrumentedAppDir = mActivityThread.mInstrumentedAppDir;
- String[] instrumentedSplitAppDirs = mActivityThread.mInstrumentedSplitAppDirs;
- String instrumentedLibDir = mActivityThread.mInstrumentedLibDir;
- String[] instrumentationLibs = null;
-
- if (mAppDir.equals(instrumentationAppDir)
- || mAppDir.equals(instrumentedAppDir)) {
- zipPaths.clear();
- zipPaths.add(instrumentationAppDir);
- if (instrumentationSplitAppDirs != null) {
- Collections.addAll(zipPaths, instrumentationSplitAppDirs);
- }
- zipPaths.add(instrumentedAppDir);
- if (instrumentedSplitAppDirs != null) {
- Collections.addAll(zipPaths, instrumentedSplitAppDirs);
- }
-
- libPaths.clear();
- libPaths.add(instrumentationLibDir);
- libPaths.add(instrumentedLibDir);
-
- if (!instrumentedAppDir.equals(instrumentationAppDir)) {
- instrumentationLibs = getLibrariesFor(instrumentationPackageName);
- }
- }
-
- apkPaths.addAll(zipPaths);
-
- if (mSharedLibraries != null) {
- for (String lib : mSharedLibraries) {
- if (!zipPaths.contains(lib)) {
- zipPaths.add(0, lib);
- }
- }
- }
-
- if (instrumentationLibs != null) {
- for (String lib : instrumentationLibs) {
- if (!zipPaths.contains(lib)) {
- zipPaths.add(0, lib);
- }
- }
- }
-
- final String zip = mIncludeCode ? TextUtils.join(File.pathSeparator, zipPaths) : "";
-
- // Add path to libraries in apk for current abi
- if (mApplicationInfo.primaryCpuAbi != null) {
- for (String apk : apkPaths) {
- libPaths.add(apk + "!/lib/" + mApplicationInfo.primaryCpuAbi);
- }
- }
-
+ makePaths(mActivityThread, mApplicationInfo, zipPaths, libPaths);
+ final String zip = TextUtils.join(File.pathSeparator, zipPaths);
+ final boolean isBundledApp = mApplicationInfo.isSystemApp()
+ && !mApplicationInfo.isUpdatedSystemApp();
String libraryPermittedPath = mDataDir;
- boolean isBundledApp = false;
-
- if (mApplicationInfo.isSystemApp() && !mApplicationInfo.isUpdatedSystemApp()) {
- isBundledApp = true;
- // Add path to system libraries to libPaths;
- // Access to system libs should be limited
- // to bundled applications; this is why updated
- // system apps are not included.
- libPaths.add(System.getProperty("java.library.path"));
-
+ if (isBundledApp) {
// This is necessary to grant bundled apps access to
// libraries located in subdirectories of /system/lib
libraryPermittedPath += File.pathSeparator +
@@ -414,15 +462,42 @@
Slog.v(ActivityThread.TAG, "Class path: " + zip +
", JNI path: " + librarySearchPath);
- // Temporarily disable logging of disk reads on the Looper thread
- // as this is early and necessary.
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ if (mClassLoader == null) {
+ // Temporarily disable logging of disk reads on the Looper thread
+ // as this is early and necessary.
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip,
- mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
- libraryPermittedPath, mBaseClassLoader);
+ classLoader = ApplicationLoaders.getDefault().getClassLoader(zip,
+ mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
+ libraryPermittedPath, mBaseClassLoader);
- StrictMode.setThreadPolicy(oldPolicy);
+ StrictMode.setThreadPolicy(oldPolicy);
+ } else if (addedPaths != null && addedPaths.size() > 0) {
+ final String add = TextUtils.join(File.pathSeparator, addedPaths);
+ ApplicationLoaders.getDefault().addPath(mClassLoader, add);
+ classLoader = mClassLoader;
+ } else {
+ classLoader = mClassLoader;
+ }
+ } else {
+ if (mClassLoader == null) {
+ if (mBaseClassLoader == null) {
+ classLoader = ClassLoader.getSystemClassLoader();
+ } else {
+ classLoader = mBaseClassLoader;
+ }
+ } else {
+ classLoader = mClassLoader;
+ }
+ }
+ return classLoader;
+ }
+
+ public ClassLoader getClassLoader() {
+ synchronized (this) {
+ if (mClassLoader == null) {
+ mClassLoader = createOrUpdateClassLoaderLocked(null /*addedPaths*/);
+ }
return mClassLoader;
}
}
@@ -1103,7 +1178,6 @@
private RuntimeException mUnbindLocation;
- private boolean mDied;
private boolean mForgotten;
private static class ConnectionInfo {
@@ -1202,7 +1276,6 @@
ServiceDispatcher.ConnectionInfo old;
synchronized (this) {
- mDied = true;
old = mActiveConnections.remove(name);
if (old == null || old.binder != service) {
// Death for someone different than who we last
@@ -1237,7 +1310,6 @@
if (service != null) {
// A new service is being connected... set it all up.
- mDied = false;
info = new ConnectionInfo();
info.binder = service;
info.deathMonitor = new DeathMonitor(name, service);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 057a4e9..16aee78 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -662,7 +662,7 @@
/**
* Notification policy configuration. Represents user-preferences for notification
- * filtering and prioritization.
+ * filtering.
*/
public static class Policy implements android.os.Parcelable {
/** Reminder notifications are prioritized. */
@@ -707,13 +707,13 @@
*/
public static final int SUPPRESSED_EFFECTS_UNSET = -1;
/**
- * Whether notification suppressed by DND should not interruption visually when the screen
- * is off.
+ * Whether notifications suppressed by DND should not interrupt visually (e.g. with
+ * notification lights or by turning the screen on) when the screen is off.
*/
public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1 << 0;
/**
- * Whether notification suppressed by DND should not interruption visually when the screen
- * is on.
+ * Whether notifications suppressed by DND should not interrupt visually when the screen
+ * is on (e.g. by peeking onto the screen).
*/
public static final int SUPPRESSED_EFFECT_SCREEN_ON = 1 << 1;
@@ -728,13 +728,27 @@
*/
public final int suppressedVisualEffects;
-
- @Deprecated
+ /**
+ * Constructs a policy for Do Not Disturb priority mode behavior.
+ *
+ * @param priorityCategories bitmask of categories of notifications that can bypass DND.
+ * @param priorityCallSenders which callers can bypass DND.
+ * @param priorityMessageSenders which message senders can bypass DND.
+ */
public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders) {
this(priorityCategories, priorityCallSenders, priorityMessageSenders,
SUPPRESSED_EFFECTS_UNSET);
}
+ /**
+ * Constructs a policy for Do Not Disturb priority mode behavior.
+ *
+ * @param priorityCategories bitmask of categories of notifications that can bypass DND.
+ * @param priorityCallSenders which callers can bypass DND.
+ * @param priorityMessageSenders which message senders can bypass DND.
+ * @param suppressedVisualEffects which visual interruptions should be suppressed from
+ * notifications that are filtered by DND.
+ */
public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders,
int suppressedVisualEffects) {
this.priorityCategories = priorityCategories;
@@ -865,7 +879,6 @@
return new Policy[size];
}
};
-
}
/**
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 94e584e..bc44553d 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -23,6 +23,7 @@
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.ResourcesImpl;
import android.content.res.ResourcesKey;
import android.hardware.display.DisplayManagerGlobal;
import android.util.ArrayMap;
@@ -250,7 +251,8 @@
} else {
config = getConfiguration();
}
- r = new Resources(assets, dm, config, compatInfo, classLoader);
+ r = new Resources(classLoader);
+ r.setImpl(new ResourcesImpl(assets, dm, config, compatInfo));
if (DEBUG) Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
+ r.getConfiguration() + " appScale=" + r.getCompatibilityInfo().applicationScale);
@@ -288,6 +290,19 @@
}
}
+ /**
+ * Removes the top level Resources for applications with the given compatibility info.
+ * @see #getTopLevelResources(String, String[], String[], String[], int, Configuration, CompatibilityInfo, ClassLoader)
+ */
+ void removeTopLevelResources(String resDir, int displayId, Configuration overrideConfiguration,
+ CompatibilityInfo compatInfo) {
+ final float scale = compatInfo.applicationScale;
+ final Configuration overrideConfigCopy = (overrideConfiguration != null)
+ ? new Configuration(overrideConfiguration) : null;
+ final ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfigCopy, scale);
+ mActiveResources.remove(key);
+ }
+
/* package */ void setDefaultLocalesLocked(LocaleList locales) {
final int bestLocale;
if (mHasNonSystemLocales) {
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 4d8d96b..6bc03f7 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1433,6 +1433,25 @@
}
/**
+ * Remove one or more currently set wallpapers, reverting to the system default
+ * display for each one. If {@link #FLAG_SET_SYSTEM} is set in the {@code which}
+ * parameter, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} will be broadcast
+ * upon success.
+ *
+ * @param which A bitwise combination of {@link #FLAG_SET_SYSTEM} or
+ * {@link #FLAG_SET_LOCK}
+ * @throws IOException If an error occurs reverting to the built-in wallpaper.
+ */
+ public void clear(int which) throws IOException {
+ if ((which & FLAG_SET_SYSTEM) != 0) {
+ clear();
+ }
+ if ((which & FLAG_SET_LOCK) != 0) {
+ clearWallpaper(FLAG_SET_LOCK, mContext.getUserId());
+ }
+ }
+
+ /**
* Open stream representing the default static image wallpaper.
*
* @hide
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5285d52..c4037f8 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -344,6 +344,68 @@
= "android.app.action.PROVISION_FINALIZATION";
/**
+ * Action: Bugreport sharing with device owner has been accepted by the user.
+ *
+ * @hide
+ */
+ public static final String ACTION_BUGREPORT_SHARING_ACCEPTED =
+ "com.android.server.action.BUGREPORT_SHARING_ACCEPTED";
+
+ /**
+ * Action: Bugreport sharing with device owner has been declined by the user.
+ *
+ * @hide
+ */
+ public static final String ACTION_BUGREPORT_SHARING_DECLINED =
+ "com.android.server.action.BUGREPORT_SHARING_DECLINED";
+
+ /**
+ * Action: Bugreport has been collected and is dispatched to {@link DevicePolicyManagerService}.
+ *
+ * @hide
+ */
+ public static final String ACTION_REMOTE_BUGREPORT_DISPATCH =
+ "android.intent.action.REMOTE_BUGREPORT_DISPATCH";
+
+ /**
+ * Extra for shared bugreport's SHA-256 hash.
+ *
+ * @hide
+ */
+ public static final String EXTRA_REMOTE_BUGREPORT_HASH =
+ "android.intent.extra.REMOTE_BUGREPORT_HASH";
+
+ /**
+ * Extra for remote bugreport notification shown type.
+ *
+ * @hide
+ */
+ public static final String EXTRA_BUGREPORT_NOTIFICATION_TYPE =
+ "android.app.extra.bugreport_notification_type";
+
+ /**
+ * Notification type for a started remote bugreport flow.
+ *
+ * @hide
+ */
+ public static final int NOTIFICATION_BUGREPORT_STARTED = 1;
+
+ /**
+ * Notification type for a bugreport that has already been accepted to be shared, but is still
+ * being taken.
+ *
+ * @hide
+ */
+ public static final int NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED = 2;
+
+ /**
+ * Notification type for a bugreport that has been taken and can be shared or declined.
+ *
+ * @hide
+ */
+ public static final int NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED = 3;
+
+ /**
* A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that
* allows a mobile device management application or NFC programmer application which starts
* managed provisioning to pass data to the management application instance after provisioning.
@@ -2750,7 +2812,7 @@
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if calling from a delegated certificate installer.
* @param alias The private key alias under which the certificate is installed.
- * @return {@code true} if the keys were both removed, {@code false} otherwise.
+ * @return {@code true} if the certificate alias no longer exists, {@code false} otherwise.
*/
public boolean removeKeyPair(@Nullable ComponentName admin, @NonNull String alias) {
try {
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index 0a0d77d..8cdfee5 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -69,4 +69,13 @@
* @return true if the uid is an active admin with the given policy.
*/
public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy);
+
+ /**
+ * Checks if a given package has a device or a profile owner for the given user
+ *
+ * @param packageName The package to check
+ * @param userId the userId to check for.
+ * @return true if package has a device or profile owner, false otherwise.
+ */
+ public abstract boolean hasDeviceOwnerOrProfileOwner(String packageName, int userId);
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 9959f27..0389085 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -530,4 +530,7 @@
String getServicesSystemSharedLibraryPackageName();
boolean isPackageDeviceAdminOnAnyUser(String packageName);
+
+ List<String> getPreviousCodePaths(in String packageName);
+
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 2cbb782..700a40d 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1042,6 +1042,11 @@
}
/** {@hide} */
+ public void setInstallFlagsDontKillApp() {
+ installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
+ }
+
+ /** {@hide} */
public void dump(IndentingPrintWriter pw) {
pw.printPair("mode", mode);
pw.printHexPair("installFlags", installFlags);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c2d1bdd..0dc856c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -538,6 +538,7 @@
INSTALL_FORCE_VOLUME_UUID,
INSTALL_FORCE_PERMISSION_PROMPT,
INSTALL_EPHEMERAL,
+ INSTALL_DONT_KILL_APP,
})
@Retention(RetentionPolicy.SOURCE)
public @interface InstallFlags {}
@@ -640,6 +641,15 @@
public static final int INSTALL_EPHEMERAL = 0x00000800;
/**
+ * Flag parameter for {@link #installPackage} to indicate that this package contains
+ * a feature split to an existing application and the existing application should not
+ * be killed during the installation process.
+ *
+ * @hide
+ */
+ public static final int INSTALL_DONT_KILL_APP = 0x00001000;
+
+ /**
* Flag parameter for
* {@link #setComponentEnabledSetting(android.content.ComponentName, int, int)} to indicate
* that you don't want to kill the app containing the component. Be careful when you set this
@@ -1088,6 +1098,7 @@
DELETE_KEEP_DATA,
DELETE_ALL_USERS,
DELETE_SYSTEM_APP,
+ DELETE_DONT_KILL_APP,
})
@Retention(RetentionPolicy.SOURCE)
public @interface DeleteFlags {}
@@ -1120,6 +1131,15 @@
public static final int DELETE_SYSTEM_APP = 0x00000004;
/**
+ * Flag parameter for {@link #deletePackage} to indicate that, if you are calling
+ * uninstall on a package that is replaced to provide new feature splits, the
+ * existing application should not be killed during the removal process.
+ *
+ * @hide
+ */
+ public static final int DELETE_DONT_KILL_APP = 0x00000008;
+
+ /**
* Return code for when package deletion succeeds. This is passed to the
* {@link IPackageDeleteObserver} if the system succeeded in deleting the
* package.
@@ -1292,6 +1312,7 @@
*
* @hide
*/
+ @SystemApi
public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1;
/**
@@ -1301,6 +1322,7 @@
*
* @hide
*/
+ @SystemApi
public static final int INTENT_FILTER_VERIFICATION_FAILURE = -1;
/**
@@ -4339,6 +4361,32 @@
throws NameNotFoundException;
/**
+ * Returns a managed-user-style badged copy of the given drawable allowing the user to
+ * distinguish it from the original drawable.
+ * The caller can specify the location in the bounds of the drawable to be
+ * badged where the badge should be applied as well as the density of the
+ * badge to be used.
+ * <p>
+ * If the original drawable is a BitmapDrawable and the backing bitmap is
+ * mutable as per {@link android.graphics.Bitmap#isMutable()}, the badging
+ * is performed in place and the original drawable is returned.
+ * </p>
+ *
+ * @param drawable The drawable to badge.
+ * @param badgeLocation Where in the bounds of the badged drawable to place
+ * the badge. If it's {@code null}, the badge is applied on top of the entire
+ * drawable being badged.
+ * @param badgeDensity The optional desired density for the badge as per
+ * {@link android.util.DisplayMetrics#densityDpi}. If it's not positive,
+ * the density of the display is used.
+ * @return A drawable that combines the original drawable and a badge as
+ * determined by the system.
+ * @hide
+ */
+ public abstract Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
+ int badgeDensity);
+
+ /**
* If the target user is a managed profile of the calling user or if the
* target user is the caller and is itself a managed profile, then this
* returns a badged copy of the given icon to be able to distinguish it from
@@ -4367,17 +4415,17 @@
* badge to be used.
* <p>
* If the original drawable is a BitmapDrawable and the backing bitmap is
- * mutable as per {@link android.graphics.Bitmap#isMutable()}, the bading
+ * mutable as per {@link android.graphics.Bitmap#isMutable()}, the badging
* is performed in place and the original drawable is returned.
* </p>
*
* @param drawable The drawable to badge.
* @param user The target user.
* @param badgeLocation Where in the bounds of the badged drawable to place
- * the badge. If not provided, the badge is applied on top of the entire
+ * the badge. If it's {@code null}, the badge is applied on top of the entire
* drawable being badged.
* @param badgeDensity The optional desired density for the badge as per
- * {@link android.util.DisplayMetrics#densityDpi}. If not provided,
+ * {@link android.util.DisplayMetrics#densityDpi}. If it's not positive,
* the density of the display is used.
* @return A drawable that combines the original drawable and a badge as
* determined by the system.
@@ -4685,8 +4733,8 @@
/**
* Allows a package listening to the
- * {@link Intent#ACTION_INTENT_FILTER_NEEDS_VERIFICATION intent filter verification
- * broadcast} to respond to the package manager. The response must include
+ * {@link Intent#ACTION_INTENT_FILTER_NEEDS_VERIFICATION} intent filter verification
+ * broadcast to respond to the package manager. The response must include
* the {@code verificationCode} which is one of
* {@link PackageManager#INTENT_FILTER_VERIFICATION_SUCCESS} or
* {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}.
@@ -4695,7 +4743,7 @@
* {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra.
* @param verificationCode either {@link PackageManager#INTENT_FILTER_VERIFICATION_SUCCESS}
* or {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}.
- * @param outFailedDomains a list of failed domains if the verificationCode is
+ * @param failedDomains a list of failed domains if the verificationCode is
* {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}, otherwise null;
* @throws SecurityException if the caller does not have the
* INTENT_FILTER_VERIFICATION_AGENT permission.
@@ -4704,7 +4752,7 @@
*/
@SystemApi
public abstract void verifyIntentFilter(int verificationId, int verificationCode,
- List<String> outFailedDomains);
+ List<String> failedDomains);
/**
* Get the status of a Domain Verification Result for an IntentFilter. This is
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 7fe7f84..89f2fc4 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -16,6 +16,8 @@
package android.content.pm;
+import android.content.pm.PackageManager.NameNotFoundException;
+
import java.util.List;
/**
@@ -125,4 +127,17 @@
* @return True a permissions review is required.
*/
public abstract boolean isPermissionsReviewRequired(String packageName, int userId);
+
+ /**
+ * Gets all of the information we know about a particular package.
+ *
+ * @param packageName The package name to find.
+ * @param userId The user under which to check.
+ *
+ * @return An {@link ApplicationInfo} containing information about the
+ * package.
+ * @throws NameNotFoundException if a package with the given name cannot be
+ * found on the system.
+ */
+ public abstract ApplicationInfo getApplicationInfo(String packageName, int userId);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ce6ddfd..bc28ff1 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -121,6 +121,10 @@
private static final int MAX_PACKAGES_PER_APK = 5;
+ public static final int APK_SIGNING_UNKNOWN = 0;
+ public static final int APK_SIGNING_V1 = 1;
+ public static final int APK_SIGNING_V2 = 2;
+
// TODO: switch outError users to PackageParserException
// TODO: refactor "codePath" to "apkPath"
@@ -1058,12 +1062,24 @@
return pkg;
}
+ public static int getApkSigningVersion(Package pkg) {
+ try {
+ if (ApkSignatureSchemeV2Verifier.hasSignature(pkg.baseCodePath)) {
+ return APK_SIGNING_V2;
+ }
+ return APK_SIGNING_V1;
+ } catch (IOException e) {
+ }
+ return APK_SIGNING_UNKNOWN;
+ }
+
/**
* Collect certificates from all the APKs described in the given package,
* populating {@link Package#mSignatures}. Also asserts that all APK
* contents are signed correctly and consistently.
*/
- public static void collectCertificates(Package pkg, int parseFlags) throws PackageParserException {
+ public static void collectCertificates(Package pkg, int parseFlags)
+ throws PackageParserException {
collectCertificatesInternal(pkg, parseFlags);
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
@@ -1074,7 +1090,8 @@
}
}
- private static void collectCertificatesInternal(Package pkg, int parseFlags) throws PackageParserException {
+ private static void collectCertificatesInternal(Package pkg, int parseFlags)
+ throws PackageParserException {
pkg.mCertificates = null;
pkg.mSignatures = null;
pkg.mSigningKeys = null;
@@ -4690,9 +4707,6 @@
// preferred up order.
public int mPreferredOrder = 0;
- // For use by package manager to keep track of where it needs to do dexopt.
- public final ArraySet<String> mDexOptPerformed = new ArraySet<>(4);
-
// For use by package manager to keep track of when a package was last used.
public long mLastPackageUsageTimeInMills;
diff --git a/core/java/android/content/res/ConfigurationBoundResourceCache.java b/core/java/android/content/res/ConfigurationBoundResourceCache.java
index fecda87..40d2a82 100644
--- a/core/java/android/content/res/ConfigurationBoundResourceCache.java
+++ b/core/java/android/content/res/ConfigurationBoundResourceCache.java
@@ -23,29 +23,19 @@
* @hide For internal use only.
*/
public class ConfigurationBoundResourceCache<T> extends ThemedResourceCache<ConstantState<T>> {
- private final Resources mResources;
-
- /**
- * Creates a cache for the given Resources instance.
- *
- * @param resources the resources to use when creating new instances
- */
- public ConfigurationBoundResourceCache(Resources resources) {
- mResources = resources;
- }
-
/**
* If the resource is cached, creates and returns a new instance of it.
*
* @param key a key that uniquely identifies the drawable resource
+ * @param resources a Resources object from which to create new instances.
* @param theme the theme where the resource will be used
* @return a new instance of the resource, or {@code null} if not in
* the cache
*/
- public T getInstance(long key, Resources.Theme theme) {
+ public T getInstance(long key, Resources resources, Resources.Theme theme) {
final ConstantState<T> entry = get(key, theme);
if (entry != null) {
- return entry.newInstance(mResources, theme);
+ return entry.newInstance(resources, theme);
}
return null;
diff --git a/core/java/android/content/res/DrawableCache.java b/core/java/android/content/res/DrawableCache.java
index ba00134..7b27fac 100644
--- a/core/java/android/content/res/DrawableCache.java
+++ b/core/java/android/content/res/DrawableCache.java
@@ -22,29 +22,19 @@
* Class which can be used to cache Drawable resources against a theme.
*/
class DrawableCache extends ThemedResourceCache<Drawable.ConstantState> {
- private final Resources mResources;
-
- /**
- * Creates a cache for the given Resources instance.
- *
- * @param resources the resources to use when creating new instances
- */
- public DrawableCache(Resources resources) {
- mResources = resources;
- }
-
/**
* If the resource is cached, creates and returns a new instance of it.
*
* @param key a key that uniquely identifies the drawable resource
+ * @param resources a Resources object from which to create new instances.
* @param theme the theme where the resource will be used
* @return a new instance of the resource, or {@code null} if not in
* the cache
*/
- public Drawable getInstance(long key, Resources.Theme theme) {
+ public Drawable getInstance(long key, Resources resources, Resources.Theme theme) {
final Drawable.ConstantState entry = get(key, theme);
if (entry != null) {
- return entry.newDrawable(mResources, theme);
+ return entry.newDrawable(resources, theme);
}
return null;
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index a54f40f..f337fe6 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -40,23 +40,17 @@
import android.annotation.XmlRes;
import android.content.pm.ActivityInfo;
import android.graphics.Movie;
-import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable.ConstantState;
import android.graphics.drawable.DrawableInflater;
-import android.icu.text.PluralRules;
import android.os.Build;
import android.os.Bundle;
-import android.os.Trace;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
-import android.util.LocaleList;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.Pools.SynchronizedPool;
-import android.util.Slog;
import android.util.TypedValue;
-import android.util.Xml;
import android.view.ViewDebug;
import android.view.ViewHierarchyEncoder;
@@ -68,8 +62,6 @@
import java.io.IOException;
import java.io.InputStream;
-import java.util.Arrays;
-import java.util.Locale;
/**
* Class for accessing an application's resources. This sits on top of the
@@ -99,51 +91,15 @@
public class Resources {
static final String TAG = "Resources";
- private static final boolean DEBUG_LOAD = false;
- private static final boolean DEBUG_CONFIG = false;
- private static final boolean TRACE_FOR_PRELOAD = false;
- private static final boolean TRACE_FOR_MISS_PRELOAD = false;
-
- private static final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigToNative(
- ActivityInfo.CONFIG_LAYOUT_DIRECTION);
-
- private static final int ID_OTHER = 0x01000004;
-
private static final Object sSync = new Object();
- // Information about preloaded resources. Note that they are not
- // protected by a lock, because while preloading in zygote we are all
- // single-threaded, and after that these are immutable.
- private static final LongSparseArray<ConstantState>[] sPreloadedDrawables;
- private static final LongSparseArray<ConstantState> sPreloadedColorDrawables
- = new LongSparseArray<>();
- private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>>
- sPreloadedComplexColors = new LongSparseArray<>();
-
- /** Size of the cyclical cache used to map XML files to blocks. */
- private static final int XML_BLOCK_CACHE_SIZE = 4;
-
- // Pool of TypedArrays targeted to this Resources object.
- final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
-
// Used by BridgeResources in layoutlib
static Resources mSystem = null;
- private static boolean sPreloaded;
+ private ResourcesImpl mResourcesImpl;
- /** Lock object used to protect access to caches and configuration. */
- private final Object mAccessLock = new Object();
-
- // These are protected by mAccessLock.
- private final Configuration mTmpConfig = new Configuration();
- private final DrawableCache mDrawableCache = new DrawableCache(this);
- private final DrawableCache mColorDrawableCache = new DrawableCache(this);
- private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache =
- new ConfigurationBoundResourceCache<>(this);
- private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
- new ConfigurationBoundResourceCache<>(this);
- private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
- new ConfigurationBoundResourceCache<>(this);
+ // Pool of TypedArrays targeted to this Resources object.
+ final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
/** Used to inflate drawable objects from XML. */
private DrawableInflater mDrawableInflater;
@@ -154,29 +110,7 @@
/** Single-item pool used to minimize TypedValue allocations. */
private TypedValue mTmpValue = new TypedValue();
- private boolean mPreloading;
-
- // Cyclical cache used for recently-accessed XML files.
- private int mLastCachedXmlBlockIndex = -1;
- private final int[] mCachedXmlBlockCookies = new int[XML_BLOCK_CACHE_SIZE];
- private final String[] mCachedXmlBlockFiles = new String[XML_BLOCK_CACHE_SIZE];
- private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[XML_BLOCK_CACHE_SIZE];
-
- final AssetManager mAssets;
final ClassLoader mClassLoader;
- final DisplayMetrics mMetrics = new DisplayMetrics();
-
- private final Configuration mConfiguration = new Configuration();
-
- private PluralRules mPluralRule;
-
- private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
-
- static {
- sPreloadedDrawables = new LongSparseArray[2];
- sPreloadedDrawables[0] = new LongSparseArray<>();
- sPreloadedDrawables[1] = new LongSparseArray<>();
- }
/**
* Returns the most appropriate default theme for the specified target SDK version.
@@ -219,32 +153,20 @@
}
/**
- * @return the inflater used to create drawable objects
- * @hide Pending API finalization.
+ * Return a global shared Resources object that provides access to only
+ * system resources (no application resources), and is not configured for
+ * the current screen (can not use dimension units, does not change based
+ * on orientation, etc).
*/
- public final DrawableInflater getDrawableInflater() {
- if (mDrawableInflater == null) {
- mDrawableInflater = new DrawableInflater(this, mClassLoader);
+ public static Resources getSystem() {
+ synchronized (sSync) {
+ Resources ret = mSystem;
+ if (ret == null) {
+ ret = new Resources();
+ mSystem = ret;
+ }
+ return ret;
}
- return mDrawableInflater;
- }
-
- /**
- * Used by AnimatorInflater.
- *
- * @hide
- */
- public ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
- return mAnimatorCache;
- }
-
- /**
- * Used by AnimatorInflater.
- *
- * @hide
- */
- public ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
- return mStateListAnimatorCache;
}
/**
@@ -275,51 +197,73 @@
* selecting/computing resource values (optional).
*/
public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
- this(assets, metrics, config, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+ this(null);
+ mResourcesImpl = new ResourcesImpl(assets, metrics, config,
+ CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
}
/**
* Creates a new Resources object with CompatibilityInfo.
*
- * @param assets Previously created AssetManager.
- * @param metrics Current display metrics to consider when
- * selecting/computing resource values.
- * @param config Desired device configuration to consider when
- * selecting/computing resource values (optional).
- * @param compatInfo this resource's compatibility info. Must not be null.
* @param classLoader class loader for the package used to load custom
* resource classes, may be {@code null} to use system
* class loader
* @hide
*/
- public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config,
- CompatibilityInfo compatInfo, @Nullable ClassLoader classLoader) {
- mAssets = assets;
+ public Resources(@Nullable ClassLoader classLoader) {
mClassLoader = classLoader == null ? ClassLoader.getSystemClassLoader() : classLoader;
- mMetrics.setToDefaults();
- if (compatInfo != null) {
- mCompatibilityInfo = compatInfo;
- }
- updateConfiguration(config, metrics);
- assets.ensureStringBlocks();
}
/**
- * Return a global shared Resources object that provides access to only
- * system resources (no application resources), and is not configured for
- * the current screen (can not use dimension units, does not change based
- * on orientation, etc).
+ * Only for creating the System resources.
*/
- public static Resources getSystem() {
- synchronized (sSync) {
- Resources ret = mSystem;
- if (ret == null) {
- ret = new Resources();
- mSystem = ret;
- }
+ private Resources() {
+ this(null);
- return ret;
+ final DisplayMetrics metrics = new DisplayMetrics();
+ metrics.setToDefaults();
+
+ final Configuration config = new Configuration();
+ config.setToDefaults();
+
+ mResourcesImpl = new ResourcesImpl(AssetManager.getSystem(), metrics, config,
+ CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
+ }
+
+ /**
+ * @hide
+ */
+ public void setImpl(ResourcesImpl impl) {
+ mResourcesImpl = impl;
+ }
+
+ /**
+ * @return the inflater used to create drawable objects
+ * @hide Pending API finalization.
+ */
+ public final DrawableInflater getDrawableInflater() {
+ if (mDrawableInflater == null) {
+ mDrawableInflater = new DrawableInflater(this, mClassLoader);
}
+ return mDrawableInflater;
+ }
+
+ /**
+ * Used by AnimatorInflater.
+ *
+ * @hide
+ */
+ public ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
+ return mResourcesImpl.getAnimatorCache();
+ }
+
+ /**
+ * Used by AnimatorInflater.
+ *
+ * @hide
+ */
+ public ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
+ return mResourcesImpl.getStateListAnimatorCache();
}
/**
@@ -337,8 +281,8 @@
* @return CharSequence The string data associated with the resource, plus
* possibly styled text information.
*/
- public CharSequence getText(@StringRes int id) throws NotFoundException {
- CharSequence res = mAssets.getResourceText(id);
+ @NonNull public CharSequence getText(@StringRes int id) throws NotFoundException {
+ CharSequence res = mResourcesImpl.getAssets().getResourceText(id);
if (res != null) {
return res;
}
@@ -366,41 +310,10 @@
* @return CharSequence The string data associated with the resource, plus
* possibly styled text information.
*/
+ @NonNull
public CharSequence getQuantityText(@PluralsRes int id, int quantity)
throws NotFoundException {
- PluralRules rule = getPluralRule();
- CharSequence res = mAssets.getResourceBagText(id,
- attrForQuantityCode(rule.select(quantity)));
- if (res != null) {
- return res;
- }
- res = mAssets.getResourceBagText(id, ID_OTHER);
- if (res != null) {
- return res;
- }
- throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
- + " quantity=" + quantity
- + " item=" + rule.select(quantity));
- }
-
- private PluralRules getPluralRule() {
- synchronized (sSync) {
- if (mPluralRule == null) {
- mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
- }
- return mPluralRule;
- }
- }
-
- private static int attrForQuantityCode(String quantityCode) {
- switch (quantityCode) {
- case PluralRules.KEYWORD_ZERO: return 0x01000005;
- case PluralRules.KEYWORD_ONE: return 0x01000006;
- case PluralRules.KEYWORD_TWO: return 0x01000007;
- case PluralRules.KEYWORD_FEW: return 0x01000008;
- case PluralRules.KEYWORD_MANY: return 0x01000009;
- default: return ID_OTHER;
- }
+ return mResourcesImpl.getQuantityText(id, quantity);
}
/**
@@ -419,12 +332,7 @@
*/
@NonNull
public String getString(@StringRes int id) throws NotFoundException {
- final CharSequence res = getText(id);
- if (res != null) {
- return res.toString();
- }
- throw new NotFoundException("String resource ID #0x"
- + Integer.toHexString(id));
+ return getText(id).toString();
}
@@ -449,7 +357,8 @@
@NonNull
public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException {
final String raw = getString(id);
- return String.format(mConfiguration.getLocales().get(0), raw, formatArgs);
+ return String.format(mResourcesImpl.getConfiguration().getLocales().get(0), raw,
+ formatArgs);
}
/**
@@ -477,10 +386,12 @@
* @return String The string data associated with the resource,
* stripped of styled text information.
*/
+ @NonNull
public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)
throws NotFoundException {
String raw = getQuantityText(id, quantity).toString();
- return String.format(mConfiguration.getLocales().get(0), raw, formatArgs);
+ return String.format(mResourcesImpl.getConfiguration().getLocales().get(0), raw,
+ formatArgs);
}
/**
@@ -503,8 +414,8 @@
* @return String The string data associated with the resource,
* stripped of styled text information.
*/
- public String getQuantityString(@PluralsRes int id, int quantity)
- throws NotFoundException {
+ @NonNull
+ public String getQuantityString(@PluralsRes int id, int quantity) throws NotFoundException {
return getQuantityText(id, quantity).toString();
}
@@ -523,7 +434,7 @@
* possibly styled text information, or def if id is 0 or not found.
*/
public CharSequence getText(@StringRes int id, CharSequence def) {
- CharSequence res = id != 0 ? mAssets.getResourceText(id) : null;
+ CharSequence res = id != 0 ? mResourcesImpl.getAssets().getResourceText(id) : null;
return res != null ? res : def;
}
@@ -538,13 +449,13 @@
*
* @return The styled text array associated with the resource.
*/
+ @NonNull
public CharSequence[] getTextArray(@ArrayRes int id) throws NotFoundException {
- CharSequence[] res = mAssets.getResourceTextArray(id);
+ CharSequence[] res = mResourcesImpl.getAssets().getResourceTextArray(id);
if (res != null) {
return res;
}
- throw new NotFoundException("Text array resource ID #0x"
- + Integer.toHexString(id));
+ throw new NotFoundException("Text array resource ID #0x" + Integer.toHexString(id));
}
/**
@@ -558,14 +469,14 @@
*
* @return The string array associated with the resource.
*/
+ @NonNull
public String[] getStringArray(@ArrayRes int id)
throws NotFoundException {
- String[] res = mAssets.getResourceStringArray(id);
+ String[] res = mResourcesImpl.getAssets().getResourceStringArray(id);
if (res != null) {
return res;
}
- throw new NotFoundException("String array resource ID #0x"
- + Integer.toHexString(id));
+ throw new NotFoundException("String array resource ID #0x" + Integer.toHexString(id));
}
/**
@@ -579,13 +490,13 @@
*
* @return The int array associated with the resource.
*/
+ @NonNull
public int[] getIntArray(@ArrayRes int id) throws NotFoundException {
- int[] res = mAssets.getArrayIntResource(id);
+ int[] res = mResourcesImpl.getAssets().getArrayIntResource(id);
if (res != null) {
return res;
}
- throw new NotFoundException("Int array resource ID #0x"
- + Integer.toHexString(id));
+ throw new NotFoundException("Int array resource ID #0x" + Integer.toHexString(id));
}
/**
@@ -601,16 +512,16 @@
* Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
* when done with it.
*/
- public TypedArray obtainTypedArray(@ArrayRes int id)
- throws NotFoundException {
- int len = mAssets.getArraySize(id);
+ @NonNull
+ public TypedArray obtainTypedArray(@ArrayRes int id) throws NotFoundException {
+ final ResourcesImpl impl = mResourcesImpl;
+ int len = impl.getAssets().getArraySize(id);
if (len < 0) {
- throw new NotFoundException("Array resource ID #0x"
- + Integer.toHexString(id));
+ throw new NotFoundException("Array resource ID #0x" + Integer.toHexString(id));
}
TypedArray array = TypedArray.obtain(this, len);
- array.mLength = mAssets.retrieveArray(id, array.mData);
+ array.mLength = impl.getAssets().retrieveArray(id, array.mData);
array.mIndices[0] = 0;
return array;
@@ -634,10 +545,12 @@
* @see #getDimensionPixelSize
*/
public float getDimension(@DimenRes int id) throws NotFoundException {
- final TypedValue value = obtainTempTypedValue(id);
+ final TypedValue value = obtainTempTypedValue();
try {
+ final ResourcesImpl impl = mResourcesImpl;
+ impl.getValue(id, value, true);
if (value.type == TypedValue.TYPE_DIMENSION) {
- return TypedValue.complexToDimension(value.data, mMetrics);
+ return TypedValue.complexToDimension(value.data, impl.getDisplayMetrics());
}
throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
+ " type #0x" + Integer.toHexString(value.type) + " is not valid");
@@ -666,10 +579,13 @@
* @see #getDimensionPixelSize
*/
public int getDimensionPixelOffset(@DimenRes int id) throws NotFoundException {
- final TypedValue value = obtainTempTypedValue(id);
+ final TypedValue value = obtainTempTypedValue();
try {
+ final ResourcesImpl impl = mResourcesImpl;
+ impl.getValue(id, value, true);
if (value.type == TypedValue.TYPE_DIMENSION) {
- return TypedValue.complexToDimensionPixelOffset(value.data, mMetrics);
+ return TypedValue.complexToDimensionPixelOffset(value.data,
+ impl.getDisplayMetrics());
}
throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
+ " type #0x" + Integer.toHexString(value.type) + " is not valid");
@@ -699,10 +615,12 @@
* @see #getDimensionPixelOffset
*/
public int getDimensionPixelSize(@DimenRes int id) throws NotFoundException {
- final TypedValue value = obtainTempTypedValue(id);
+ final TypedValue value = obtainTempTypedValue();
try {
+ final ResourcesImpl impl = mResourcesImpl;
+ impl.getValue(id, value, true);
if (value.type == TypedValue.TYPE_DIMENSION) {
- return TypedValue.complexToDimensionPixelSize(value.data, mMetrics);
+ return TypedValue.complexToDimensionPixelSize(value.data, impl.getDisplayMetrics());
}
throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
+ " type #0x" + Integer.toHexString(value.type) + " is not valid");
@@ -729,8 +647,9 @@
* @throws NotFoundException Throws NotFoundException if the given ID does not exist.
*/
public float getFraction(@FractionRes int id, int base, int pbase) {
- final TypedValue value = obtainTempTypedValue(id);
+ final TypedValue value = obtainTempTypedValue();
try {
+ mResourcesImpl.getValue(id, value, true);
if (value.type == TypedValue.TYPE_FRACTION) {
return TypedValue.complexToFraction(value.data, base, pbase);
}
@@ -800,9 +719,11 @@
*/
public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme)
throws NotFoundException {
- final TypedValue value = obtainTempTypedValue(id);
+ final TypedValue value = obtainTempTypedValue();
try {
- return loadDrawable(value, id, theme);
+ final ResourcesImpl impl = mResourcesImpl;
+ impl.getValue(id, value, true);
+ return impl.loadDrawable(this, value, id, theme, true);
} finally {
releaseTempTypedValue(value);
}
@@ -855,14 +776,16 @@
* not exist.
*/
public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) {
- final TypedValue value = obtainTempTypedValue(id);
+ final TypedValue value = obtainTempTypedValue();
try {
- getValueForDensity(id, density, value, true);
+ final ResourcesImpl impl = mResourcesImpl;
+ impl.getValueForDensity(id, density, value, true);
// If the drawable's XML lives in our current density qualifier,
// it's okay to use a scaled version from the cache. Otherwise, we
// need to actually load the drawable from XML.
- final boolean useCache = value.density == mMetrics.densityDpi;
+ final DisplayMetrics metrics = impl.getDisplayMetrics();
+ final boolean useCache = value.density == metrics.densityDpi;
/*
* Pretend the requested density is actually the display density. If
@@ -873,18 +796,23 @@
*/
if (value.density > 0 && value.density != TypedValue.DENSITY_NONE) {
if (value.density == density) {
- value.density = mMetrics.densityDpi;
+ value.density = metrics.densityDpi;
} else {
- value.density = (value.density * mMetrics.densityDpi) / density;
+ value.density = (value.density * metrics.densityDpi) / density;
}
}
-
- return loadDrawable(value, id, theme, useCache);
+ return impl.loadDrawable(this, value, id, theme, useCache);
} finally {
releaseTempTypedValue(value);
}
}
+ @NonNull
+ Drawable loadDrawable(@NonNull TypedValue value, int id, @Nullable Theme theme)
+ throws NotFoundException {
+ return mResourcesImpl.loadDrawable(this, value, id, theme, true);
+ }
+
/**
* Return a movie object associated with the particular resource ID.
* @param id The desired resource identifier, as generated by the aapt
@@ -894,13 +822,12 @@
*
*/
public Movie getMovie(@RawRes int id) throws NotFoundException {
- InputStream is = openRawResource(id);
- Movie movie = Movie.decodeStream(is);
+ final InputStream is = openRawResource(id);
+ final Movie movie = Movie.decodeStream(is);
try {
is.close();
- }
- catch (java.io.IOException e) {
- // don't care, since the return value is valid
+ } catch (IOException e) {
+ // No one cares.
}
return movie;
}
@@ -944,8 +871,10 @@
*/
@ColorInt
public int getColor(@ColorRes int id, @Nullable Theme theme) throws NotFoundException {
- final TypedValue value = obtainTempTypedValue(id);
+ final TypedValue value = obtainTempTypedValue();
try {
+ final ResourcesImpl impl = mResourcesImpl;
+ impl.getValue(id, value, true);
if (value.type >= TypedValue.TYPE_FIRST_INT
&& value.type <= TypedValue.TYPE_LAST_INT) {
return value.data;
@@ -954,7 +883,7 @@
+ " type #0x" + Integer.toHexString(value.type) + " is not valid");
}
- final ColorStateList csl = loadColorStateList(value, id, theme);
+ final ColorStateList csl = impl.loadColorStateList(this, value, id, theme);
return csl.getDefaultColor();
} finally {
releaseTempTypedValue(value);
@@ -1012,14 +941,27 @@
@Nullable
public ColorStateList getColorStateList(@ColorRes int id, @Nullable Theme theme)
throws NotFoundException {
- final TypedValue value = obtainTempTypedValue(id);
+ final TypedValue value = obtainTempTypedValue();
try {
- return loadColorStateList(value, id, theme);
+ final ResourcesImpl impl = mResourcesImpl;
+ impl.getValue(id, value, true);
+ return impl.loadColorStateList(this, value, id, theme);
} finally {
releaseTempTypedValue(value);
}
}
+ @Nullable
+ ColorStateList loadColorStateList(@NonNull TypedValue value, int id, @Nullable Theme theme)
+ throws NotFoundException {
+ return mResourcesImpl.loadColorStateList(this, value, id, theme);
+ }
+
+ @Nullable
+ public ComplexColor loadComplexColor(@NonNull TypedValue value, int id, @Nullable Theme theme) {
+ return mResourcesImpl.loadComplexColor(this, value, id, theme);
+ }
+
/**
* Return a boolean associated with a particular resource ID. This can be
* used with any integral resource value, and will return true if it is
@@ -1034,8 +976,9 @@
* @return Returns the boolean value contained in the resource.
*/
public boolean getBoolean(@BoolRes int id) throws NotFoundException {
- final TypedValue value = obtainTempTypedValue(id);
+ final TypedValue value = obtainTempTypedValue();
try {
+ mResourcesImpl.getValue(id, value, true);
if (value.type >= TypedValue.TYPE_FIRST_INT
&& value.type <= TypedValue.TYPE_LAST_INT) {
return value.data != 0;
@@ -1059,8 +1002,9 @@
* @return Returns the integer value contained in the resource.
*/
public int getInteger(@IntegerRes int id) throws NotFoundException {
- final TypedValue value = obtainTempTypedValue(id);
+ final TypedValue value = obtainTempTypedValue();
try {
+ mResourcesImpl.getValue(id, value, true);
if (value.type >= TypedValue.TYPE_FIRST_INT
&& value.type <= TypedValue.TYPE_LAST_INT) {
return value.data;
@@ -1086,8 +1030,9 @@
* @hide Pending API council approval.
*/
public float getFloat(int id) {
- final TypedValue value = obtainTempTypedValue(id);
+ final TypedValue value = obtainTempTypedValue();
try {
+ mResourcesImpl.getValue(id, value, true);
if (value.type == TypedValue.TYPE_FLOAT) {
return value.getFloat();
}
@@ -1195,20 +1140,6 @@
}
/**
- * Returns a TypedValue populated with data for the specified resource ID
- * that's suitable for temporary use. The obtained TypedValue should be
- * released using {@link #releaseTempTypedValue(TypedValue)}.
- *
- * @param id the resource ID for which data should be obtained
- * @return a populated typed value suitable for temporary use
- */
- private TypedValue obtainTempTypedValue(@AnyRes int id) {
- final TypedValue value = obtainTempTypedValue();
- getValue(id, value, true);
- return value;
- }
-
- /**
* Returns a TypedValue suitable for temporary use. The obtained TypedValue
* should be released using {@link #releaseTempTypedValue(TypedValue)}.
*
@@ -1257,17 +1188,7 @@
*/
public InputStream openRawResource(@RawRes int id, TypedValue value)
throws NotFoundException {
- getValue(id, value, true);
-
- try {
- return mAssets.openNonAsset(value.assetCookie, value.string.toString(),
- AssetManager.ACCESS_STREAMING);
- } catch (Exception e) {
- NotFoundException rnf = new NotFoundException("File " + value.string.toString() +
- " from drawable resource ID #0x" + Integer.toHexString(id));
- rnf.initCause(e);
- throw rnf;
- }
+ return mResourcesImpl.openRawResource(id, value);
}
/**
@@ -1293,12 +1214,9 @@
*/
public AssetFileDescriptor openRawResourceFd(@RawRes int id)
throws NotFoundException {
- final TypedValue value = obtainTempTypedValue(id);
+ final TypedValue value = obtainTempTypedValue();
try {
- return mAssets.openNonAssetFd(value.assetCookie, value.string.toString());
- } catch (Exception e) {
- throw new NotFoundException("File " + value.string.toString() + " from drawable "
- + "resource ID #0x" + Integer.toHexString(id), e);
+ return mResourcesImpl.openRawResourceFd(id, value);
} finally {
releaseTempTypedValue(value);
}
@@ -1321,12 +1239,7 @@
*/
public void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
throws NotFoundException {
- boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
- if (found) {
- return;
- }
- throw new NotFoundException("Resource ID #0x"
- + Integer.toHexString(id));
+ mResourcesImpl.getValue(id, outValue, resolveRefs);
}
/**
@@ -1344,11 +1257,7 @@
*/
public void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
boolean resolveRefs) throws NotFoundException {
- boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
- if (found) {
- return;
- }
- throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
+ mResourcesImpl.getValueForDensity(id, density, outValue, resolveRefs);
}
/**
@@ -1373,12 +1282,7 @@
*/
public void getValue(String name, TypedValue outValue, boolean resolveRefs)
throws NotFoundException {
- int id = getIdentifier(name, "string", null);
- if (id != 0) {
- getValue(id, outValue, resolveRefs);
- return;
- }
- throw new NotFoundException("String resource name " + name);
+ mResourcesImpl.getValue(name, outValue, resolveRefs);
}
/**
@@ -1397,6 +1301,15 @@
* retrieve XML attributes with style and theme information applied.
*/
public final class Theme {
+ private ResourcesImpl.ThemeImpl mThemeImpl;
+
+ private Theme() {
+ }
+
+ void setImpl(ResourcesImpl.ThemeImpl impl) {
+ mThemeImpl = impl;
+ }
+
/**
* Place new attribute values into the theme. The style resource
* specified by <var>resid</var> will be retrieved from this Theme's
@@ -1415,12 +1328,7 @@
* if not already defined in the theme.
*/
public void applyStyle(int resId, boolean force) {
- synchronized (mKey) {
- AssetManager.applyThemeStyle(mTheme, resId, force);
-
- mThemeResId = resId;
- mKey.append(resId, force);
- }
+ mThemeImpl.applyStyle(resId, force);
}
/**
@@ -1433,14 +1341,7 @@
* @param other The existing Theme to copy from.
*/
public void setTo(Theme other) {
- synchronized (mKey) {
- synchronized (other.mKey) {
- AssetManager.copyTheme(mTheme, other.mTheme);
-
- mThemeResId = other.mThemeResId;
- mKey.setTo(other.getKey());
- }
- }
+ mThemeImpl.setTo(other.mThemeImpl);
}
/**
@@ -1463,13 +1364,7 @@
* @see #obtainStyledAttributes(AttributeSet, int[], int, int)
*/
public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
- synchronized (mKey) {
- final int len = attrs.length;
- final TypedArray array = TypedArray.obtain(Resources.this, len);
- array.mTheme = this;
- AssetManager.applyStyle(mTheme, 0, 0, 0, attrs, array.mData, array.mIndices);
- return array;
- }
+ return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, 0);
}
/**
@@ -1494,13 +1389,7 @@
*/
public TypedArray obtainStyledAttributes(@StyleRes int resId, @StyleableRes int[] attrs)
throws NotFoundException {
- synchronized (mKey) {
- final int len = attrs.length;
- final TypedArray array = TypedArray.obtain(Resources.this, len);
- array.mTheme = this;
- AssetManager.applyStyle(mTheme, 0, resId, 0, attrs, array.mData, array.mIndices);
- return array;
- }
+ return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, resId);
}
/**
@@ -1553,23 +1442,7 @@
*/
public TypedArray obtainStyledAttributes(AttributeSet set,
@StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
- synchronized (mKey) {
- final int len = attrs.length;
- final TypedArray array = TypedArray.obtain(Resources.this, len);
-
- // XXX note that for now we only work with compiled XML files.
- // To support generic XML files we will need to manually parse
- // out the attributes from the XML file (applying type information
- // contained in the resources and such).
- final XmlBlock.Parser parser = (XmlBlock.Parser) set;
- AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
- parser != null ? parser.mParseState : 0,
- attrs, array.mData, array.mIndices);
- array.mTheme = this;
- array.mXml = parser;
-
- return array;
- }
+ return mThemeImpl.obtainStyledAttributes(this, set, attrs, defStyleAttr, defStyleRes);
}
/**
@@ -1588,20 +1461,7 @@
*/
@NonNull
public TypedArray resolveAttributes(@NonNull int[] values, @NonNull int[] attrs) {
- synchronized (mKey) {
- final int len = attrs.length;
- if (values == null || len != values.length) {
- throw new IllegalArgumentException(
- "Base attribute values must the same length as attrs");
- }
-
- final TypedArray array = TypedArray.obtain(Resources.this, len);
- AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
- array.mTheme = this;
- array.mXml = null;
-
- return array;
- }
+ return mThemeImpl.resolveAttributes(this, values, attrs);
}
/**
@@ -1622,9 +1482,7 @@
* <var>outValue</var> is valid, else false.
*/
public boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
- synchronized (mKey) {
- return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
- }
+ return mThemeImpl.resolveAttribute(resid, outValue, resolveRefs);
}
/**
@@ -1634,7 +1492,7 @@
* @hide
*/
public int[] getAllAttributes() {
- return mAssets.getStyleAttributes(getAppliedStyleResId());
+ return mThemeImpl.getAllAttributes();
}
/**
@@ -1670,11 +1528,7 @@
* @see ActivityInfo
*/
public int getChangingConfigurations() {
- synchronized (mKey) {
- final int nativeChangingConfig =
- AssetManager.getThemeChangingConfigurations(mTheme);
- return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
- }
+ return mThemeImpl.getChangingConfigurations();
}
/**
@@ -1685,43 +1539,23 @@
* @param prefix Text to prefix each line printed.
*/
public void dump(int priority, String tag, String prefix) {
- synchronized (mKey) {
- AssetManager.dumpTheme(mTheme, priority, tag, prefix);
- }
+ mThemeImpl.dump(priority, tag, prefix);
}
- @Override
- protected void finalize() throws Throwable {
- super.finalize();
- mAssets.releaseTheme(mTheme);
- }
-
- /*package*/ Theme() {
- mAssets = Resources.this.mAssets;
- mTheme = mAssets.createTheme();
- }
-
- /** Unique key for the series of styles applied to this theme. */
- private final ThemeKey mKey = new ThemeKey();
-
- @SuppressWarnings("hiding")
- private final AssetManager mAssets;
- private final long mTheme;
-
- /** Resource identifier for the theme. */
- private int mThemeResId = 0;
-
// Needed by layoutlib.
/*package*/ long getNativeTheme() {
- return mTheme;
+ return mThemeImpl.getNativeTheme();
}
/*package*/ int getAppliedStyleResId() {
- return mThemeResId;
+ return mThemeImpl.getAppliedStyleResId();
}
- /*package*/ ThemeKey getKey() {
- return mKey;
+ /**
+ * @hide
+ */
+ public ThemeKey getKey() {
+ return mThemeImpl.getKey();
}
private String getResourceNameFromHexString(String hexString) {
@@ -1729,7 +1563,7 @@
}
/**
- * Parses {@link #mKey} and returns a String array that holds pairs of
+ * Parses {@link #getKey()} and returns a String array that holds pairs of
* adjacent Theme data: resource name followed by whether or not it was
* forced, as specified by {@link #applyStyle(int, boolean)}.
*
@@ -1737,21 +1571,7 @@
*/
@ViewDebug.ExportedProperty(category = "theme", hasAdjacentMapping = true)
public String[] getTheme() {
- synchronized (mKey) {
- final int N = mKey.mCount;
- final String[] themes = new String[N * 2];
- for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) {
- final int resId = mKey.mResId[j];
- final boolean forced = mKey.mForce[j];
- try {
- themes[i] = getResourceName(resId);
- } catch (NotFoundException e) {
- themes[i] = Integer.toHexString(i);
- }
- themes[i + 1] = forced ? "forced" : "not forced";
- }
- return themes;
- }
+ return mThemeImpl.getTheme();
}
/** @hide */
@@ -1772,16 +1592,7 @@
* @hide
*/
public void rebase() {
- synchronized (mKey) {
- AssetManager.clearTheme(mTheme);
-
- // Reapply the same styles in the same order.
- for (int i = 0; i < mKey.mCount; i++) {
- final int resId = mKey.mResId[i];
- final boolean force = mKey.mForce[i];
- AssetManager.applyThemeStyle(mTheme, resId, force);
- }
- }
+ mThemeImpl.rebase();
}
}
@@ -1870,7 +1681,9 @@
* @return Theme The newly created Theme container.
*/
public final Theme newTheme() {
- return new Theme();
+ Theme theme = new Theme();
+ theme.setImpl(mResourcesImpl.newThemeImpl());
+ return theme;
}
/**
@@ -1894,7 +1707,7 @@
// out the attributes from the XML file (applying type information
// contained in the resources and such).
XmlBlock.Parser parser = (XmlBlock.Parser)set;
- mAssets.retrieveAttributes(parser.mParseState, attrs,
+ mResourcesImpl.getAssets().retrieveAttributes(parser.mParseState, attrs,
array.mData, array.mIndices);
array.mXml = parser;
@@ -1905,151 +1718,16 @@
/**
* Store the newly updated configuration.
*/
- public void updateConfiguration(Configuration config,
- DisplayMetrics metrics) {
+ public void updateConfiguration(Configuration config, DisplayMetrics metrics) {
updateConfiguration(config, metrics, null);
}
/**
* @hide
*/
- public void updateConfiguration(Configuration config,
- DisplayMetrics metrics, CompatibilityInfo compat) {
- synchronized (mAccessLock) {
- if (false) {
- Slog.i(TAG, "**** Updating config of " + this + ": old config is "
- + mConfiguration + " old compat is " + mCompatibilityInfo);
- Slog.i(TAG, "**** Updating config of " + this + ": new config is "
- + config + " new compat is " + compat);
- }
- if (compat != null) {
- mCompatibilityInfo = compat;
- }
- if (metrics != null) {
- mMetrics.setTo(metrics);
- }
- // NOTE: We should re-arrange this code to create a Display
- // with the CompatibilityInfo that is used everywhere we deal
- // with the display in relation to this app, rather than
- // doing the conversion here. This impl should be okay because
- // we make sure to return a compatible display in the places
- // where there are public APIs to retrieve the display... but
- // it would be cleaner and more maintainble to just be
- // consistently dealing with a compatible display everywhere in
- // the framework.
- mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
-
- final int configChanges = calcConfigChanges(config);
-
- LocaleList locales = mConfiguration.getLocales();
- if (locales.isEmpty()) {
- locales = LocaleList.getAdjustedDefault();
- mConfiguration.setLocales(locales);
- }
- if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
- mMetrics.densityDpi = mConfiguration.densityDpi;
- mMetrics.density = mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
- }
- mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
-
- final int width, height;
- if (mMetrics.widthPixels >= mMetrics.heightPixels) {
- width = mMetrics.widthPixels;
- height = mMetrics.heightPixels;
- } else {
- //noinspection SuspiciousNameCombination
- width = mMetrics.heightPixels;
- //noinspection SuspiciousNameCombination
- height = mMetrics.widthPixels;
- }
-
- final int keyboardHidden;
- if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
- && mConfiguration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
- keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
- } else {
- keyboardHidden = mConfiguration.keyboardHidden;
- }
-
- mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
- adjustLanguageTag(locales.get(0).toLanguageTag()),
- mConfiguration.orientation,
- mConfiguration.touchscreen,
- mConfiguration.densityDpi, mConfiguration.keyboard,
- keyboardHidden, mConfiguration.navigation, width, height,
- mConfiguration.smallestScreenWidthDp,
- mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
- mConfiguration.screenLayout, mConfiguration.uiMode,
- Build.VERSION.RESOURCES_SDK_INT);
-
- if (DEBUG_CONFIG) {
- Slog.i(TAG, "**** Updating config of " + this + ": final config is "
- + mConfiguration + " final compat is " + mCompatibilityInfo);
- }
-
- mDrawableCache.onConfigurationChange(configChanges);
- mColorDrawableCache.onConfigurationChange(configChanges);
- mComplexColorCache.onConfigurationChange(configChanges);
- mAnimatorCache.onConfigurationChange(configChanges);
- mStateListAnimatorCache.onConfigurationChange(configChanges);
-
- flushLayoutCache();
- }
- synchronized (sSync) {
- if (mPluralRule != null) {
- mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
- }
- }
- }
-
- /**
- * Called by ConfigurationBoundResourceCacheTest via reflection.
- */
- private int calcConfigChanges(Configuration config) {
- int configChanges = 0xfffffff;
- if (config != null) {
- mTmpConfig.setTo(config);
- int density = config.densityDpi;
- if (density == Configuration.DENSITY_DPI_UNDEFINED) {
- density = mMetrics.noncompatDensityDpi;
- }
-
- mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
-
- if (mTmpConfig.getLocales().isEmpty()) {
- mTmpConfig.setLocales(LocaleList.getDefault());
- }
- configChanges = mConfiguration.updateFrom(mTmpConfig);
- configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
- }
- return configChanges;
- }
-
- /**
- * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated)
- * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively.
- *
- * All released versions of android prior to "L" used the deprecated language
- * tags, so we will need to support them for backwards compatibility.
- *
- * Note that this conversion needs to take place *after* the call to
- * {@code toLanguageTag} because that will convert all the deprecated codes to
- * the new ones, even if they're set manually.
- */
- private static String adjustLanguageTag(String languageTag) {
- final int separator = languageTag.indexOf('-');
- final String language;
- final String remainder;
-
- if (separator == -1) {
- language = languageTag;
- remainder = "";
- } else {
- language = languageTag.substring(0, separator);
- remainder = languageTag.substring(separator);
- }
-
- return Locale.adjustLanguageCode(language) + remainder;
+ public void updateConfiguration(Configuration config, DisplayMetrics metrics,
+ CompatibilityInfo compat) {
+ mResourcesImpl.updateConfiguration(config, metrics, compat);
}
/**
@@ -2074,9 +1752,7 @@
* @return The resource's current display metrics.
*/
public DisplayMetrics getDisplayMetrics() {
- if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels
- + "x" + mMetrics.heightPixels + " " + mMetrics.density);
- return mMetrics;
+ return mResourcesImpl.getDisplayMetrics();
}
/**
@@ -2086,13 +1762,13 @@
* @return The resource's current configuration.
*/
public Configuration getConfiguration() {
- return mConfiguration;
+ return mResourcesImpl.getConfiguration();
}
/** @hide */
public Configuration[] getSizeConfigurations() {
- return mAssets.getSizeConfigurations();
- };
+ return mResourcesImpl.getSizeConfigurations();
+ }
/**
* Return the compatibility mode information for the application.
@@ -2102,7 +1778,7 @@
* @hide
*/
public CompatibilityInfo getCompatibilityInfo() {
- return mCompatibilityInfo;
+ return mResourcesImpl.getCompatibilityInfo();
}
/**
@@ -2111,8 +1787,7 @@
*/
public void setCompatibilityInfo(CompatibilityInfo ci) {
if (ci != null) {
- mCompatibilityInfo = ci;
- updateConfiguration(mConfiguration, mMetrics);
+ mResourcesImpl.updateConfiguration(null, null, ci);
}
}
@@ -2137,15 +1812,7 @@
* resource was found. (0 is not a valid resource ID.)
*/
public int getIdentifier(String name, String defType, String defPackage) {
- if (name == null) {
- throw new NullPointerException("name is null");
- }
- try {
- return Integer.parseInt(name);
- } catch (Exception e) {
- // Ignore
- }
- return mAssets.getResourceIdentifier(name, defType, defPackage);
+ return mResourcesImpl.getIdentifier(name, defType, defPackage);
}
/**
@@ -2172,10 +1839,7 @@
* @see #getResourceEntryName
*/
public String getResourceName(@AnyRes int resid) throws NotFoundException {
- String str = mAssets.getResourceName(resid);
- if (str != null) return str;
- throw new NotFoundException("Unable to find resource ID #0x"
- + Integer.toHexString(resid));
+ return mResourcesImpl.getResourceName(resid);
}
/**
@@ -2191,10 +1855,7 @@
* @see #getResourceName
*/
public String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
- String str = mAssets.getResourcePackageName(resid);
- if (str != null) return str;
- throw new NotFoundException("Unable to find resource ID #0x"
- + Integer.toHexString(resid));
+ return mResourcesImpl.getResourcePackageName(resid);
}
/**
@@ -2210,10 +1871,7 @@
* @see #getResourceName
*/
public String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
- String str = mAssets.getResourceTypeName(resid);
- if (str != null) return str;
- throw new NotFoundException("Unable to find resource ID #0x"
- + Integer.toHexString(resid));
+ return mResourcesImpl.getResourceTypeName(resid);
}
/**
@@ -2229,10 +1887,7 @@
* @see #getResourceName
*/
public String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
- String str = mAssets.getResourceEntryName(resid);
- if (str != null) return str;
- throw new NotFoundException("Unable to find resource ID #0x"
- + Integer.toHexString(resid));
+ return mResourcesImpl.getResourceEntryName(resid);
}
/**
@@ -2335,7 +1990,7 @@
* Retrieve underlying AssetManager storage for these resources.
*/
public final AssetManager getAssets() {
- return mAssets;
+ return mResourcesImpl.getAssets();
}
/**
@@ -2344,19 +1999,7 @@
* tools.
*/
public final void flushLayoutCache() {
- synchronized (mCachedXmlBlocks) {
- Arrays.fill(mCachedXmlBlockCookies, 0);
- Arrays.fill(mCachedXmlBlockFiles, null);
-
- final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
- for (int i = 0; i < XML_BLOCK_CACHE_SIZE; i++) {
- final XmlBlock oldBlock = cachedXmlBlocks[i];
- if (oldBlock != null) {
- oldBlock.close();
- }
- }
- Arrays.fill(cachedXmlBlocks, null);
- }
+ mResourcesImpl.flushLayoutCache();
}
/**
@@ -2365,15 +2008,7 @@
* {@hide}
*/
public final void startPreloading() {
- synchronized (sSync) {
- if (sPreloaded) {
- throw new IllegalStateException("Resources already preloaded");
- }
- sPreloaded = true;
- mPreloading = true;
- mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE;
- updateConfiguration(null, null);
- }
+ mResourcesImpl.startPreloading();
}
/**
@@ -2381,441 +2016,14 @@
* to normal Resources operation.
*/
public final void finishPreloading() {
- if (mPreloading) {
- mPreloading = false;
- flushLayoutCache();
- }
+ mResourcesImpl.finishPreloading();
}
/**
* @hide
*/
public LongSparseArray<ConstantState> getPreloadedDrawables() {
- return sPreloadedDrawables[0];
- }
-
- private boolean verifyPreloadConfig(int changingConfigurations, int allowVarying,
- int resourceId, String name) {
- // We allow preloading of resources even if they vary by font scale (which
- // doesn't impact resource selection) or density (which we handle specially by
- // simply turning off all preloading), as well as any other configs specified
- // by the caller.
- if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE |
- ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) {
- String resName;
- try {
- resName = getResourceName(resourceId);
- } catch (NotFoundException e) {
- resName = "?";
- }
- // This should never happen in production, so we should log a
- // warning even if we're not debugging.
- Log.w(TAG, "Preloaded " + name + " resource #0x"
- + Integer.toHexString(resourceId)
- + " (" + resName + ") that varies with configuration!!");
- return false;
- }
- if (TRACE_FOR_PRELOAD) {
- String resName;
- try {
- resName = getResourceName(resourceId);
- } catch (NotFoundException e) {
- resName = "?";
- }
- Log.w(TAG, "Preloading " + name + " resource #0x"
- + Integer.toHexString(resourceId)
- + " (" + resName + ")");
- }
- return true;
- }
-
- @Nullable
- Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException {
- return loadDrawable(value, id, theme, true);
- }
-
- @Nullable
- Drawable loadDrawable(TypedValue value, int id, Theme theme, boolean useCache)
- throws NotFoundException {
- try {
- if (TRACE_FOR_PRELOAD) {
- // Log only framework resources
- if ((id >>> 24) == 0x1) {
- final String name = getResourceName(id);
- if (name != null) {
- Log.d("PreloadDrawable", name);
- }
- }
- }
-
- final boolean isColorDrawable;
- final DrawableCache caches;
- final long key;
- if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
- && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
- isColorDrawable = true;
- caches = mColorDrawableCache;
- key = value.data;
- } else {
- isColorDrawable = false;
- caches = mDrawableCache;
- key = (((long) value.assetCookie) << 32) | value.data;
- }
-
- // First, check whether we have a cached version of this drawable
- // that was inflated against the specified theme. Skip the cache if
- // we're currently preloading or we're not using the cache.
- if (!mPreloading && useCache) {
- final Drawable cachedDrawable = caches.getInstance(key, theme);
- if (cachedDrawable != null) {
- return cachedDrawable;
- }
- }
-
- // Next, check preloaded drawables. Preloaded drawables may contain
- // unresolved theme attributes.
- final ConstantState cs;
- if (isColorDrawable) {
- cs = sPreloadedColorDrawables.get(key);
- } else {
- cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
- }
-
- Drawable dr;
- if (cs != null) {
- dr = cs.newDrawable(this);
- } else if (isColorDrawable) {
- dr = new ColorDrawable(value.data);
- } else {
- dr = loadDrawableForCookie(value, id, null);
- }
-
- // Determine if the drawable has unresolved theme attributes. If it
- // does, we'll need to apply a theme and store it in a theme-specific
- // cache.
- final boolean canApplyTheme = dr != null && dr.canApplyTheme();
- if (canApplyTheme && theme != null) {
- dr = dr.mutate();
- dr.applyTheme(theme);
- dr.clearMutated();
- }
-
- // If we were able to obtain a drawable, store it in the appropriate
- // cache: preload, not themed, null theme, or theme-specific. Don't
- // pollute the cache with drawables loaded from a foreign density.
- if (dr != null && useCache) {
- dr.setChangingConfigurations(value.changingConfigurations);
- cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
- }
-
- return dr;
- } catch (Exception e) {
- String name;
- try {
- name = getResourceName(id);
- } catch (NotFoundException e2) {
- name = "(missing name)";
- }
-
- // The target drawable might fail to load for any number of
- // reasons, but we always want to include the resource name.
- // Since the client already expects this method to throw a
- // NotFoundException, just throw one of those.
- final NotFoundException nfe = new NotFoundException("Drawable " + name
- + " with resource ID #0x" + Integer.toHexString(id), e);
- nfe.setStackTrace(new StackTraceElement[0]);
- throw nfe;
- }
- }
-
- private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches,
- Theme theme, boolean usesTheme, long key, Drawable dr) {
- final ConstantState cs = dr.getConstantState();
- if (cs == null) {
- return;
- }
-
- if (mPreloading) {
- final int changingConfigs = cs.getChangingConfigurations();
- if (isColorDrawable) {
- if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) {
- sPreloadedColorDrawables.put(key, cs);
- }
- } else {
- if (verifyPreloadConfig(
- changingConfigs, LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) {
- if ((changingConfigs & LAYOUT_DIR_CONFIG) == 0) {
- // If this resource does not vary based on layout direction,
- // we can put it in all of the preload maps.
- sPreloadedDrawables[0].put(key, cs);
- sPreloadedDrawables[1].put(key, cs);
- } else {
- // Otherwise, only in the layout dir we loaded it for.
- sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs);
- }
- }
- }
- } else {
- synchronized (mAccessLock) {
- caches.put(key, theme, cs, usesTheme);
- }
- }
- }
-
- /**
- * Loads a drawable from XML or resources stream.
- */
- private Drawable loadDrawableForCookie(TypedValue value, int id, Theme theme) {
- if (value.string == null) {
- throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
- + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
- }
-
- final String file = value.string.toString();
-
- if (TRACE_FOR_MISS_PRELOAD) {
- // Log only framework resources
- if ((id >>> 24) == 0x1) {
- final String name = getResourceName(id);
- if (name != null) {
- Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id)
- + ": " + name + " at " + file);
- }
- }
- }
-
- if (DEBUG_LOAD) {
- Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
- }
-
- final Drawable dr;
-
- Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
- try {
- if (file.endsWith(".xml")) {
- final XmlResourceParser rp = loadXmlResourceParser(
- file, id, value.assetCookie, "drawable");
- dr = Drawable.createFromXml(this, rp, theme);
- rp.close();
- } else {
- final InputStream is = mAssets.openNonAsset(
- value.assetCookie, file, AssetManager.ACCESS_STREAMING);
- dr = Drawable.createFromResourceStream(this, value, is, file, null);
- is.close();
- }
- } catch (Exception e) {
- Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
- final NotFoundException rnf = new NotFoundException(
- "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
- rnf.initCause(e);
- throw rnf;
- }
- Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
-
- return dr;
- }
-
- /**
- * Given the value and id, we can get the XML filename as in value.data, based on that, we
- * first try to load CSL from the cache. If not found, try to get from the constant state.
- * Last, parse the XML and generate the CSL.
- */
- private ComplexColor loadComplexColorFromName(Theme theme, TypedValue value, int id) {
- final long key = (((long) value.assetCookie) << 32) | value.data;
- final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
- ComplexColor complexColor = cache.getInstance(key, theme);
- if (complexColor != null) {
- return complexColor;
- }
-
- final android.content.res.ConstantState<ComplexColor> factory =
- sPreloadedComplexColors.get(key);
-
- if (factory != null) {
- complexColor = factory.newInstance(this, theme);
- }
- if (complexColor == null) {
- complexColor = loadComplexColorForCookie(value, id, theme);
- }
-
- if (complexColor != null) {
- if (mPreloading) {
- if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
- "color")) {
- sPreloadedComplexColors.put(key, complexColor.getConstantState());
- }
- } else {
- cache.put(key, theme, complexColor.getConstantState());
- }
- }
- return complexColor;
- }
-
- @Nullable
- public ComplexColor loadComplexColor(@NonNull TypedValue value, int id, Theme theme) {
- if (TRACE_FOR_PRELOAD) {
- // Log only framework resources
- if ((id >>> 24) == 0x1) {
- final String name = getResourceName(id);
- if (name != null) android.util.Log.d("loadComplexColor", name);
- }
- }
-
- final long key = (((long) value.assetCookie) << 32) | value.data;
-
- // Handle inline color definitions.
- if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
- && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
- return getColorStateListFromInt(value, key);
- }
-
- final String file = value.string.toString();
-
- ComplexColor complexColor;
- if (file.endsWith(".xml")) {
- try {
- complexColor = loadComplexColorFromName(theme, value, id);
- } catch (Exception e) {
- final NotFoundException rnf = new NotFoundException(
- "File " + file + " from complex color resource ID #0x"
- + Integer.toHexString(id));
- rnf.initCause(e);
- throw rnf;
- }
- } else {
- throw new NotFoundException(
- "File " + file + " from drawable resource ID #0x"
- + Integer.toHexString(id) + ": .xml extension required");
- }
-
- return complexColor;
- }
-
- @Nullable
- ColorStateList loadColorStateList(TypedValue value, int id, Theme theme)
- throws NotFoundException {
- if (TRACE_FOR_PRELOAD) {
- // Log only framework resources
- if ((id >>> 24) == 0x1) {
- final String name = getResourceName(id);
- if (name != null) android.util.Log.d("PreloadColorStateList", name);
- }
- }
-
- final long key = (((long) value.assetCookie) << 32) | value.data;
-
- // Handle inline color definitions.
- if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
- && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
- return getColorStateListFromInt(value, key);
- }
-
- ComplexColor complexColor = loadComplexColorFromName(theme, value, id);
- if (complexColor != null && complexColor instanceof ColorStateList) {
- return (ColorStateList) complexColor;
- }
-
- throw new NotFoundException(
- "Can't find ColorStateList from drawable resource ID #0x"
- + Integer.toHexString(id));
- }
-
- @NonNull
- private ColorStateList getColorStateListFromInt(@NonNull TypedValue value, long key) {
- ColorStateList csl;
- final android.content.res.ConstantState<ComplexColor> factory =
- sPreloadedComplexColors.get(key);
- if (factory != null) {
- return (ColorStateList) factory.newInstance();
- }
-
- csl = ColorStateList.valueOf(value.data);
-
- if (mPreloading) {
- if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
- "color")) {
- sPreloadedComplexColors.put(key, csl.getConstantState());
- }
- }
-
- return csl;
- }
-
- /**
- * Load a ComplexColor based on the XML file content. The result can be a GradientColor or
- * ColorStateList. Note that pure color will be wrapped into a ColorStateList.
- *
- * We deferred the parser creation to this function b/c we need to differentiate b/t gradient
- * and selector tag.
- *
- * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
- */
- @Nullable
- private ComplexColor loadComplexColorForCookie(TypedValue value, int id, Theme theme) {
- if (value.string == null) {
- throw new UnsupportedOperationException(
- "Can't convert to ComplexColor: type=0x" + value.type);
- }
-
- final String file = value.string.toString();
-
- if (TRACE_FOR_MISS_PRELOAD) {
- // Log only framework resources
- if ((id >>> 24) == 0x1) {
- final String name = getResourceName(id);
- if (name != null) {
- Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id)
- + ": " + name + " at " + file);
- }
- }
- }
-
- if (DEBUG_LOAD) {
- Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file);
- }
-
- ComplexColor complexColor = null;
-
- Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
- if (file.endsWith(".xml")) {
- try {
- final XmlResourceParser parser = loadXmlResourceParser(
- file, id, value.assetCookie, "ComplexColor");
-
- final AttributeSet attrs = Xml.asAttributeSet(parser);
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- // Seek parser to start tag.
- }
- if (type != XmlPullParser.START_TAG) {
- throw new XmlPullParserException("No start tag found");
- }
-
- final String name = parser.getName();
- if (name.equals("gradient")) {
- complexColor = GradientColor.createFromXmlInner(this, parser, attrs, theme);
- } else if (name.equals("selector")) {
- complexColor = ColorStateList.createFromXmlInner(this, parser, attrs, theme);
- }
- parser.close();
- } catch (Exception e) {
- Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
- final NotFoundException rnf = new NotFoundException(
- "File " + file + " from ComplexColor resource ID #0x"
- + Integer.toHexString(id));
- rnf.initCause(e);
- throw rnf;
- }
- } else {
- Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
- throw new NotFoundException(
- "File " + file + " from drawable resource ID #0x"
- + Integer.toHexString(id) + ": .xml extension required");
- }
- Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
-
- return complexColor;
+ return mResourcesImpl.getPreloadedDrawables();
}
/**
@@ -2829,10 +2037,12 @@
@NonNull
XmlResourceParser loadXmlResourceParser(@AnyRes int id, @NonNull String type)
throws NotFoundException {
- final TypedValue value = obtainTempTypedValue(id);
+ final TypedValue value = obtainTempTypedValue();
try {
+ final ResourcesImpl impl = mResourcesImpl;
+ impl.getValue(id, value, true);
if (value.type == TypedValue.TYPE_STRING) {
- return loadXmlResourceParser(value.string.toString(), id,
+ return impl.loadXmlResourceParser(value.string.toString(), id,
value.assetCookie, type);
}
throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
@@ -2853,49 +2063,9 @@
* @throws NotFoundException if the file could not be loaded
*/
@NonNull
- XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id,
- int assetCookie, @NonNull String type) throws NotFoundException {
- if (id != 0) {
- try {
- synchronized (mCachedXmlBlocks) {
- final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies;
- final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
- final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
- // First see if this block is in our cache.
- final int num = cachedXmlBlockFiles.length;
- for (int i = 0; i < num; i++) {
- if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null
- && cachedXmlBlockFiles[i].equals(file)) {
- return cachedXmlBlocks[i].newParser();
- }
- }
-
- // Not in the cache, create a new block and put it at
- // the next slot in the cache.
- final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file);
- if (block != null) {
- final int pos = (mLastCachedXmlBlockIndex + 1) % num;
- mLastCachedXmlBlockIndex = pos;
- final XmlBlock oldBlock = cachedXmlBlocks[pos];
- if (oldBlock != null) {
- oldBlock.close();
- }
- cachedXmlBlockCookies[pos] = assetCookie;
- cachedXmlBlockFiles[pos] = file;
- cachedXmlBlocks[pos] = block;
- return block.newParser();
- }
- }
- } catch (Exception e) {
- final NotFoundException rnf = new NotFoundException("File " + file
- + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id));
- rnf.initCause(e);
- throw rnf;
- }
- }
-
- throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x"
- + Integer.toHexString(id));
+ XmlResourceParser loadXmlResourceParser(String file, int id, int assetCookie,
+ String type) throws NotFoundException {
+ return mResourcesImpl.loadXmlResourceParser(file, id, assetCookie, type);
}
/**
@@ -2911,16 +2081,4 @@
}
return theme.obtainStyledAttributes(set, attrs, 0, 0);
}
-
- private Resources() {
- mAssets = AssetManager.getSystem();
- mClassLoader = ClassLoader.getSystemClassLoader();
- // NOTE: Intentionally leaving this uninitialized (all values set
- // to zero), so that anyone who tries to do something that requires
- // metrics will get a very wrong value.
- mConfiguration.setToDefaults();
- mMetrics.setToDefaults();
- updateConfiguration(null, null);
- mAssets.ensureStringBlocks();
- }
}
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
new file mode 100644
index 0000000..2ffd372
--- /dev/null
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -0,0 +1,1140 @@
+/*
+ * Copyright (C) 2016 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.content.res;
+
+import android.animation.Animator;
+import android.animation.StateListAnimator;
+import android.annotation.AnyRes;
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.PluralsRes;
+import android.annotation.RawRes;
+import android.annotation.StyleRes;
+import android.annotation.StyleableRes;
+import android.content.pm.ActivityInfo;
+import android.content.res.Resources.NotFoundException;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.icu.text.PluralRules;
+import android.os.Build;
+import android.os.Trace;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.LocaleList;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.Slog;
+import android.util.TypedValue;
+import android.util.Xml;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Locale;
+
+/**
+ * @hide
+ */
+public class ResourcesImpl {
+ static final String TAG = "Resources";
+
+ private static final boolean DEBUG_LOAD = false;
+ private static final boolean DEBUG_CONFIG = false;
+ private static final boolean TRACE_FOR_PRELOAD = false;
+ private static final boolean TRACE_FOR_MISS_PRELOAD = false;
+
+ private static final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigToNative(
+ ActivityInfo.CONFIG_LAYOUT_DIRECTION);
+
+ private static final int ID_OTHER = 0x01000004;
+
+ private static final Object sSync = new Object();
+
+ private static boolean sPreloaded;
+ private boolean mPreloading;
+
+ // Information about preloaded resources. Note that they are not
+ // protected by a lock, because while preloading in zygote we are all
+ // single-threaded, and after that these are immutable.
+ private static final LongSparseArray<Drawable.ConstantState>[] sPreloadedDrawables;
+ private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables
+ = new LongSparseArray<>();
+ private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>>
+ sPreloadedComplexColors = new LongSparseArray<>();
+
+ /** Lock object used to protect access to caches and configuration. */
+ private final Object mAccessLock = new Object();
+
+ // These are protected by mAccessLock.
+ private final Configuration mTmpConfig = new Configuration();
+ private final DrawableCache mDrawableCache = new DrawableCache();
+ private final DrawableCache mColorDrawableCache = new DrawableCache();
+ private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache =
+ new ConfigurationBoundResourceCache<>();
+ private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
+ new ConfigurationBoundResourceCache<>();
+ private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
+ new ConfigurationBoundResourceCache<>();
+
+ /** Size of the cyclical cache used to map XML files to blocks. */
+ private static final int XML_BLOCK_CACHE_SIZE = 4;
+
+ // Cyclical cache used for recently-accessed XML files.
+ private int mLastCachedXmlBlockIndex = -1;
+ private final int[] mCachedXmlBlockCookies = new int[XML_BLOCK_CACHE_SIZE];
+ private final String[] mCachedXmlBlockFiles = new String[XML_BLOCK_CACHE_SIZE];
+ private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[XML_BLOCK_CACHE_SIZE];
+
+
+ final AssetManager mAssets;
+ final DisplayMetrics mMetrics = new DisplayMetrics();
+
+ private PluralRules mPluralRule;
+
+ private final Configuration mConfiguration = new Configuration();
+ private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
+
+ static {
+ sPreloadedDrawables = new LongSparseArray[2];
+ sPreloadedDrawables[0] = new LongSparseArray<>();
+ sPreloadedDrawables[1] = new LongSparseArray<>();
+ }
+
+ /**
+ * Creates a new ResourcesImpl object with CompatibilityInfo.
+ *
+ * @param assets Previously created AssetManager.
+ * @param metrics Current display metrics to consider when
+ * selecting/computing resource values.
+ * @param config Desired device configuration to consider when
+ * selecting/computing resource values (optional).
+ * @param compatInfo this resource's compatibility info. Must not be null.
+ */
+ public ResourcesImpl(AssetManager assets, DisplayMetrics metrics, Configuration config,
+ CompatibilityInfo compatInfo) {
+ mAssets = assets;
+ mMetrics.setToDefaults();
+ updateConfiguration(config, metrics, compatInfo);
+ mAssets.ensureStringBlocks();
+ }
+
+ AssetManager getAssets() {
+ return mAssets;
+ }
+
+ DisplayMetrics getDisplayMetrics() {
+ if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels
+ + "x" + mMetrics.heightPixels + " " + mMetrics.density);
+ return mMetrics;
+ }
+
+ Configuration getConfiguration() {
+ return mConfiguration;
+ }
+
+ Configuration[] getSizeConfigurations() {
+ return mAssets.getSizeConfigurations();
+ }
+
+ CompatibilityInfo getCompatibilityInfo() {
+ return mCompatibilityInfo;
+ }
+
+ private PluralRules getPluralRule() {
+ synchronized (sSync) {
+ if (mPluralRule == null) {
+ mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
+ }
+ return mPluralRule;
+ }
+ }
+
+ void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
+ throws NotFoundException {
+ boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
+ if (found) {
+ return;
+ }
+ throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
+ }
+
+ void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
+ boolean resolveRefs) throws NotFoundException {
+ boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
+ if (found) {
+ return;
+ }
+ throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
+ }
+
+ void getValue(String name, TypedValue outValue, boolean resolveRefs)
+ throws NotFoundException {
+ int id = getIdentifier(name, "string", null);
+ if (id != 0) {
+ getValue(id, outValue, resolveRefs);
+ return;
+ }
+ throw new NotFoundException("String resource name " + name);
+ }
+
+ int getIdentifier(String name, String defType, String defPackage) {
+ if (name == null) {
+ throw new NullPointerException("name is null");
+ }
+ try {
+ return Integer.parseInt(name);
+ } catch (Exception e) {
+ // Ignore
+ }
+ return mAssets.getResourceIdentifier(name, defType, defPackage);
+ }
+
+ @NonNull
+ String getResourceName(@AnyRes int resid) throws NotFoundException {
+ String str = mAssets.getResourceName(resid);
+ if (str != null) return str;
+ throw new NotFoundException("Unable to find resource ID #0x"
+ + Integer.toHexString(resid));
+ }
+
+ @NonNull
+ String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
+ String str = mAssets.getResourcePackageName(resid);
+ if (str != null) return str;
+ throw new NotFoundException("Unable to find resource ID #0x"
+ + Integer.toHexString(resid));
+ }
+
+ @NonNull
+ String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
+ String str = mAssets.getResourceTypeName(resid);
+ if (str != null) return str;
+ throw new NotFoundException("Unable to find resource ID #0x"
+ + Integer.toHexString(resid));
+ }
+
+ @NonNull
+ String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
+ String str = mAssets.getResourceEntryName(resid);
+ if (str != null) return str;
+ throw new NotFoundException("Unable to find resource ID #0x"
+ + Integer.toHexString(resid));
+ }
+
+ @NonNull
+ CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException {
+ PluralRules rule = getPluralRule();
+ CharSequence res = mAssets.getResourceBagText(id,
+ attrForQuantityCode(rule.select(quantity)));
+ if (res != null) {
+ return res;
+ }
+ res = mAssets.getResourceBagText(id, ID_OTHER);
+ if (res != null) {
+ return res;
+ }
+ throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
+ + " quantity=" + quantity
+ + " item=" + rule.select(quantity));
+ }
+
+ private static int attrForQuantityCode(String quantityCode) {
+ switch (quantityCode) {
+ case PluralRules.KEYWORD_ZERO: return 0x01000005;
+ case PluralRules.KEYWORD_ONE: return 0x01000006;
+ case PluralRules.KEYWORD_TWO: return 0x01000007;
+ case PluralRules.KEYWORD_FEW: return 0x01000008;
+ case PluralRules.KEYWORD_MANY: return 0x01000009;
+ default: return ID_OTHER;
+ }
+ }
+
+ @NonNull
+ AssetFileDescriptor openRawResourceFd(@RawRes int id, TypedValue tempValue)
+ throws NotFoundException {
+ getValue(id, tempValue, true);
+ try {
+ return mAssets.openNonAssetFd(tempValue.assetCookie, tempValue.string.toString());
+ } catch (Exception e) {
+ throw new NotFoundException("File " + tempValue.string.toString() + " from drawable "
+ + "resource ID #0x" + Integer.toHexString(id), e);
+ }
+ }
+
+ @NonNull
+ InputStream openRawResource(@RawRes int id, TypedValue value) throws NotFoundException {
+ getValue(id, value, true);
+ try {
+ return mAssets.openNonAsset(value.assetCookie, value.string.toString(),
+ AssetManager.ACCESS_STREAMING);
+ } catch (Exception e) {
+ NotFoundException rnf = new NotFoundException("File " + value.string.toString() +
+ " from drawable resource ID #0x" + Integer.toHexString(id));
+ rnf.initCause(e);
+ throw rnf;
+ }
+ }
+
+ ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
+ return mAnimatorCache;
+ }
+
+ ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
+ return mStateListAnimatorCache;
+ }
+
+ void updateConfiguration(Configuration config, DisplayMetrics metrics,
+ CompatibilityInfo compat) {
+ synchronized (mAccessLock) {
+ if (false) {
+ Slog.i(TAG, "**** Updating config of " + this + ": old config is "
+ + mConfiguration + " old compat is " + mCompatibilityInfo);
+ Slog.i(TAG, "**** Updating config of " + this + ": new config is "
+ + config + " new compat is " + compat);
+ }
+ if (compat != null) {
+ mCompatibilityInfo = compat;
+ }
+ if (metrics != null) {
+ mMetrics.setTo(metrics);
+ }
+ // NOTE: We should re-arrange this code to create a Display
+ // with the CompatibilityInfo that is used everywhere we deal
+ // with the display in relation to this app, rather than
+ // doing the conversion here. This impl should be okay because
+ // we make sure to return a compatible display in the places
+ // where there are public APIs to retrieve the display... but
+ // it would be cleaner and more maintainble to just be
+ // consistently dealing with a compatible display everywhere in
+ // the framework.
+ mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
+
+ final int configChanges = calcConfigChanges(config);
+
+ LocaleList locales = mConfiguration.getLocales();
+ if (locales.isEmpty()) {
+ locales = LocaleList.getAdjustedDefault();
+ mConfiguration.setLocales(locales);
+ }
+ if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
+ mMetrics.densityDpi = mConfiguration.densityDpi;
+ mMetrics.density = mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ }
+ mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
+
+ final int width, height;
+ if (mMetrics.widthPixels >= mMetrics.heightPixels) {
+ width = mMetrics.widthPixels;
+ height = mMetrics.heightPixels;
+ } else {
+ //noinspection SuspiciousNameCombination
+ width = mMetrics.heightPixels;
+ //noinspection SuspiciousNameCombination
+ height = mMetrics.widthPixels;
+ }
+
+ final int keyboardHidden;
+ if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
+ && mConfiguration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
+ keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
+ } else {
+ keyboardHidden = mConfiguration.keyboardHidden;
+ }
+
+ mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
+ adjustLanguageTag(locales.get(0).toLanguageTag()),
+ mConfiguration.orientation,
+ mConfiguration.touchscreen,
+ mConfiguration.densityDpi, mConfiguration.keyboard,
+ keyboardHidden, mConfiguration.navigation, width, height,
+ mConfiguration.smallestScreenWidthDp,
+ mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
+ mConfiguration.screenLayout, mConfiguration.uiMode,
+ Build.VERSION.RESOURCES_SDK_INT);
+
+ if (DEBUG_CONFIG) {
+ Slog.i(TAG, "**** Updating config of " + this + ": final config is "
+ + mConfiguration + " final compat is " + mCompatibilityInfo);
+ }
+
+ mDrawableCache.onConfigurationChange(configChanges);
+ mColorDrawableCache.onConfigurationChange(configChanges);
+ mComplexColorCache.onConfigurationChange(configChanges);
+ mAnimatorCache.onConfigurationChange(configChanges);
+ mStateListAnimatorCache.onConfigurationChange(configChanges);
+
+ flushLayoutCache();
+ }
+ synchronized (sSync) {
+ if (mPluralRule != null) {
+ mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
+ }
+ }
+ }
+
+ /**
+ * Called by ConfigurationBoundResourceCacheTest via reflection.
+ */
+ private int calcConfigChanges(Configuration config) {
+ int configChanges = 0xfffffff;
+ if (config != null) {
+ mTmpConfig.setTo(config);
+ int density = config.densityDpi;
+ if (density == Configuration.DENSITY_DPI_UNDEFINED) {
+ density = mMetrics.noncompatDensityDpi;
+ }
+
+ mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
+
+ if (mTmpConfig.getLocales().isEmpty()) {
+ mTmpConfig.setLocales(LocaleList.getDefault());
+ }
+ configChanges = mConfiguration.updateFrom(mTmpConfig);
+ configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
+ }
+ return configChanges;
+ }
+
+ /**
+ * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated)
+ * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively.
+ *
+ * All released versions of android prior to "L" used the deprecated language
+ * tags, so we will need to support them for backwards compatibility.
+ *
+ * Note that this conversion needs to take place *after* the call to
+ * {@code toLanguageTag} because that will convert all the deprecated codes to
+ * the new ones, even if they're set manually.
+ */
+ private static String adjustLanguageTag(String languageTag) {
+ final int separator = languageTag.indexOf('-');
+ final String language;
+ final String remainder;
+
+ if (separator == -1) {
+ language = languageTag;
+ remainder = "";
+ } else {
+ language = languageTag.substring(0, separator);
+ remainder = languageTag.substring(separator);
+ }
+
+ return Locale.adjustLanguageCode(language) + remainder;
+ }
+
+ /**
+ * Call this to remove all cached loaded layout resources from the
+ * Resources object. Only intended for use with performance testing
+ * tools.
+ */
+ public void flushLayoutCache() {
+ synchronized (mCachedXmlBlocks) {
+ Arrays.fill(mCachedXmlBlockCookies, 0);
+ Arrays.fill(mCachedXmlBlockFiles, null);
+
+ final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
+ for (int i = 0; i < XML_BLOCK_CACHE_SIZE; i++) {
+ final XmlBlock oldBlock = cachedXmlBlocks[i];
+ if (oldBlock != null) {
+ oldBlock.close();
+ }
+ }
+ Arrays.fill(cachedXmlBlocks, null);
+ }
+ }
+
+ @Nullable
+ Drawable loadDrawable(Resources wrapper, TypedValue value, int id, Resources.Theme theme,
+ boolean useCache) throws NotFoundException {
+ try {
+ if (TRACE_FOR_PRELOAD) {
+ // Log only framework resources
+ if ((id >>> 24) == 0x1) {
+ final String name = getResourceName(id);
+ if (name != null) {
+ Log.d("PreloadDrawable", name);
+ }
+ }
+ }
+
+ final boolean isColorDrawable;
+ final DrawableCache caches;
+ final long key;
+ if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
+ && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+ isColorDrawable = true;
+ caches = mColorDrawableCache;
+ key = value.data;
+ } else {
+ isColorDrawable = false;
+ caches = mDrawableCache;
+ key = (((long) value.assetCookie) << 32) | value.data;
+ }
+
+ // First, check whether we have a cached version of this drawable
+ // that was inflated against the specified theme. Skip the cache if
+ // we're currently preloading or we're not using the cache.
+ if (!mPreloading && useCache) {
+ final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
+ if (cachedDrawable != null) {
+ return cachedDrawable;
+ }
+ }
+
+ // Next, check preloaded drawables. Preloaded drawables may contain
+ // unresolved theme attributes.
+ final Drawable.ConstantState cs;
+ if (isColorDrawable) {
+ cs = sPreloadedColorDrawables.get(key);
+ } else {
+ cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
+ }
+
+ Drawable dr;
+ if (cs != null) {
+ dr = cs.newDrawable(wrapper);
+ } else if (isColorDrawable) {
+ dr = new ColorDrawable(value.data);
+ } else {
+ dr = loadDrawableForCookie(wrapper, value, id, null);
+ }
+
+ // Determine if the drawable has unresolved theme attributes. If it
+ // does, we'll need to apply a theme and store it in a theme-specific
+ // cache.
+ final boolean canApplyTheme = dr != null && dr.canApplyTheme();
+ if (canApplyTheme && theme != null) {
+ dr = dr.mutate();
+ dr.applyTheme(theme);
+ dr.clearMutated();
+ }
+
+ // If we were able to obtain a drawable, store it in the appropriate
+ // cache: preload, not themed, null theme, or theme-specific. Don't
+ // pollute the cache with drawables loaded from a foreign density.
+ if (dr != null && useCache) {
+ dr.setChangingConfigurations(value.changingConfigurations);
+ cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
+ }
+
+ return dr;
+ } catch (Exception e) {
+ String name;
+ try {
+ name = getResourceName(id);
+ } catch (NotFoundException e2) {
+ name = "(missing name)";
+ }
+
+ // The target drawable might fail to load for any number of
+ // reasons, but we always want to include the resource name.
+ // Since the client already expects this method to throw a
+ // NotFoundException, just throw one of those.
+ final NotFoundException nfe = new NotFoundException("Drawable " + name
+ + " with resource ID #0x" + Integer.toHexString(id), e);
+ nfe.setStackTrace(new StackTraceElement[0]);
+ throw nfe;
+ }
+ }
+
+ private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches,
+ Resources.Theme theme, boolean usesTheme, long key, Drawable dr) {
+ final Drawable.ConstantState cs = dr.getConstantState();
+ if (cs == null) {
+ return;
+ }
+
+ if (mPreloading) {
+ final int changingConfigs = cs.getChangingConfigurations();
+ if (isColorDrawable) {
+ if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) {
+ sPreloadedColorDrawables.put(key, cs);
+ }
+ } else {
+ if (verifyPreloadConfig(
+ changingConfigs, LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) {
+ if ((changingConfigs & LAYOUT_DIR_CONFIG) == 0) {
+ // If this resource does not vary based on layout direction,
+ // we can put it in all of the preload maps.
+ sPreloadedDrawables[0].put(key, cs);
+ sPreloadedDrawables[1].put(key, cs);
+ } else {
+ // Otherwise, only in the layout dir we loaded it for.
+ sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs);
+ }
+ }
+ }
+ } else {
+ synchronized (mAccessLock) {
+ caches.put(key, theme, cs, usesTheme);
+ }
+ }
+ }
+
+ private boolean verifyPreloadConfig(int changingConfigurations, int allowVarying,
+ int resourceId, String name) {
+ // We allow preloading of resources even if they vary by font scale (which
+ // doesn't impact resource selection) or density (which we handle specially by
+ // simply turning off all preloading), as well as any other configs specified
+ // by the caller.
+ if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE |
+ ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) {
+ String resName;
+ try {
+ resName = getResourceName(resourceId);
+ } catch (NotFoundException e) {
+ resName = "?";
+ }
+ // This should never happen in production, so we should log a
+ // warning even if we're not debugging.
+ Log.w(TAG, "Preloaded " + name + " resource #0x"
+ + Integer.toHexString(resourceId)
+ + " (" + resName + ") that varies with configuration!!");
+ return false;
+ }
+ if (TRACE_FOR_PRELOAD) {
+ String resName;
+ try {
+ resName = getResourceName(resourceId);
+ } catch (NotFoundException e) {
+ resName = "?";
+ }
+ Log.w(TAG, "Preloading " + name + " resource #0x"
+ + Integer.toHexString(resourceId)
+ + " (" + resName + ")");
+ }
+ return true;
+ }
+
+ /**
+ * Loads a drawable from XML or resources stream.
+ */
+ private Drawable loadDrawableForCookie(Resources wrapper, TypedValue value, int id,
+ Resources.Theme theme) {
+ if (value.string == null) {
+ throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
+ + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
+ }
+
+ final String file = value.string.toString();
+
+ if (TRACE_FOR_MISS_PRELOAD) {
+ // Log only framework resources
+ if ((id >>> 24) == 0x1) {
+ final String name = getResourceName(id);
+ if (name != null) {
+ Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id)
+ + ": " + name + " at " + file);
+ }
+ }
+ }
+
+ if (DEBUG_LOAD) {
+ Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
+ }
+
+ final Drawable dr;
+
+ Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
+ try {
+ if (file.endsWith(".xml")) {
+ final XmlResourceParser rp = loadXmlResourceParser(
+ file, id, value.assetCookie, "drawable");
+ dr = Drawable.createFromXml(wrapper, rp, theme);
+ rp.close();
+ } else {
+ final InputStream is = mAssets.openNonAsset(
+ value.assetCookie, file, AssetManager.ACCESS_STREAMING);
+ dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
+ is.close();
+ }
+ } catch (Exception e) {
+ Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+ final NotFoundException rnf = new NotFoundException(
+ "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
+ rnf.initCause(e);
+ throw rnf;
+ }
+ Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+
+ return dr;
+ }
+
+ /**
+ * Given the value and id, we can get the XML filename as in value.data, based on that, we
+ * first try to load CSL from the cache. If not found, try to get from the constant state.
+ * Last, parse the XML and generate the CSL.
+ */
+ private ComplexColor loadComplexColorFromName(Resources wrapper, Resources.Theme theme,
+ TypedValue value, int id) {
+ final long key = (((long) value.assetCookie) << 32) | value.data;
+ final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
+ ComplexColor complexColor = cache.getInstance(key, wrapper, theme);
+ if (complexColor != null) {
+ return complexColor;
+ }
+
+ final android.content.res.ConstantState<ComplexColor> factory =
+ sPreloadedComplexColors.get(key);
+
+ if (factory != null) {
+ complexColor = factory.newInstance(wrapper, theme);
+ }
+ if (complexColor == null) {
+ complexColor = loadComplexColorForCookie(wrapper, value, id, theme);
+ }
+
+ if (complexColor != null) {
+ if (mPreloading) {
+ if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
+ "color")) {
+ sPreloadedComplexColors.put(key, complexColor.getConstantState());
+ }
+ } else {
+ cache.put(key, theme, complexColor.getConstantState());
+ }
+ }
+ return complexColor;
+ }
+
+ @Nullable
+ ComplexColor loadComplexColor(Resources wrapper, @NonNull TypedValue value, int id,
+ Resources.Theme theme) {
+ if (TRACE_FOR_PRELOAD) {
+ // Log only framework resources
+ if ((id >>> 24) == 0x1) {
+ final String name = getResourceName(id);
+ if (name != null) android.util.Log.d("loadComplexColor", name);
+ }
+ }
+
+ final long key = (((long) value.assetCookie) << 32) | value.data;
+
+ // Handle inline color definitions.
+ if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
+ && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+ return getColorStateListFromInt(value, key);
+ }
+
+ final String file = value.string.toString();
+
+ ComplexColor complexColor;
+ if (file.endsWith(".xml")) {
+ try {
+ complexColor = loadComplexColorFromName(wrapper, theme, value, id);
+ } catch (Exception e) {
+ final NotFoundException rnf = new NotFoundException(
+ "File " + file + " from complex color resource ID #0x"
+ + Integer.toHexString(id));
+ rnf.initCause(e);
+ throw rnf;
+ }
+ } else {
+ throw new NotFoundException(
+ "File " + file + " from drawable resource ID #0x"
+ + Integer.toHexString(id) + ": .xml extension required");
+ }
+
+ return complexColor;
+ }
+
+ @Nullable
+ ColorStateList loadColorStateList(Resources wrapper, TypedValue value, int id,
+ Resources.Theme theme)
+ throws NotFoundException {
+ if (TRACE_FOR_PRELOAD) {
+ // Log only framework resources
+ if ((id >>> 24) == 0x1) {
+ final String name = getResourceName(id);
+ if (name != null) android.util.Log.d("PreloadColorStateList", name);
+ }
+ }
+
+ final long key = (((long) value.assetCookie) << 32) | value.data;
+
+ // Handle inline color definitions.
+ if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
+ && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+ return getColorStateListFromInt(value, key);
+ }
+
+ ComplexColor complexColor = loadComplexColorFromName(wrapper, theme, value, id);
+ if (complexColor != null && complexColor instanceof ColorStateList) {
+ return (ColorStateList) complexColor;
+ }
+
+ throw new NotFoundException(
+ "Can't find ColorStateList from drawable resource ID #0x"
+ + Integer.toHexString(id));
+ }
+
+ @NonNull
+ private ColorStateList getColorStateListFromInt(@NonNull TypedValue value, long key) {
+ ColorStateList csl;
+ final android.content.res.ConstantState<ComplexColor> factory =
+ sPreloadedComplexColors.get(key);
+ if (factory != null) {
+ return (ColorStateList) factory.newInstance();
+ }
+
+ csl = ColorStateList.valueOf(value.data);
+
+ if (mPreloading) {
+ if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
+ "color")) {
+ sPreloadedComplexColors.put(key, csl.getConstantState());
+ }
+ }
+
+ return csl;
+ }
+
+ /**
+ * Load a ComplexColor based on the XML file content. The result can be a GradientColor or
+ * ColorStateList. Note that pure color will be wrapped into a ColorStateList.
+ *
+ * We deferred the parser creation to this function b/c we need to differentiate b/t gradient
+ * and selector tag.
+ *
+ * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
+ */
+ @Nullable
+ private ComplexColor loadComplexColorForCookie(Resources wrapper, TypedValue value, int id,
+ Resources.Theme theme) {
+ if (value.string == null) {
+ throw new UnsupportedOperationException(
+ "Can't convert to ComplexColor: type=0x" + value.type);
+ }
+
+ final String file = value.string.toString();
+
+ if (TRACE_FOR_MISS_PRELOAD) {
+ // Log only framework resources
+ if ((id >>> 24) == 0x1) {
+ final String name = getResourceName(id);
+ if (name != null) {
+ Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id)
+ + ": " + name + " at " + file);
+ }
+ }
+ }
+
+ if (DEBUG_LOAD) {
+ Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file);
+ }
+
+ ComplexColor complexColor = null;
+
+ Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
+ if (file.endsWith(".xml")) {
+ try {
+ final XmlResourceParser parser = loadXmlResourceParser(
+ file, id, value.assetCookie, "ComplexColor");
+
+ final AttributeSet attrs = Xml.asAttributeSet(parser);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Seek parser to start tag.
+ }
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException("No start tag found");
+ }
+
+ final String name = parser.getName();
+ if (name.equals("gradient")) {
+ complexColor = GradientColor.createFromXmlInner(wrapper, parser, attrs, theme);
+ } else if (name.equals("selector")) {
+ complexColor = ColorStateList.createFromXmlInner(wrapper, parser, attrs, theme);
+ }
+ parser.close();
+ } catch (Exception e) {
+ Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+ final NotFoundException rnf = new NotFoundException(
+ "File " + file + " from ComplexColor resource ID #0x"
+ + Integer.toHexString(id));
+ rnf.initCause(e);
+ throw rnf;
+ }
+ } else {
+ Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+ throw new NotFoundException(
+ "File " + file + " from drawable resource ID #0x"
+ + Integer.toHexString(id) + ": .xml extension required");
+ }
+ Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+
+ return complexColor;
+ }
+
+ /**
+ * Loads an XML parser for the specified file.
+ *
+ * @param file the path for the XML file to parse
+ * @param id the resource identifier for the file
+ * @param assetCookie the asset cookie for the file
+ * @param type the type of resource (used for logging)
+ * @return a parser for the specified XML file
+ * @throws NotFoundException if the file could not be loaded
+ */
+ @NonNull
+ XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id,
+ int assetCookie, @NonNull String type)
+ throws NotFoundException {
+ if (id != 0) {
+ try {
+ synchronized (mCachedXmlBlocks) {
+ final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies;
+ final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
+ final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
+ // First see if this block is in our cache.
+ final int num = cachedXmlBlockFiles.length;
+ for (int i = 0; i < num; i++) {
+ if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null
+ && cachedXmlBlockFiles[i].equals(file)) {
+ return cachedXmlBlocks[i].newParser();
+ }
+ }
+
+ // Not in the cache, create a new block and put it at
+ // the next slot in the cache.
+ final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file);
+ if (block != null) {
+ final int pos = (mLastCachedXmlBlockIndex + 1) % num;
+ mLastCachedXmlBlockIndex = pos;
+ final XmlBlock oldBlock = cachedXmlBlocks[pos];
+ if (oldBlock != null) {
+ oldBlock.close();
+ }
+ cachedXmlBlockCookies[pos] = assetCookie;
+ cachedXmlBlockFiles[pos] = file;
+ cachedXmlBlocks[pos] = block;
+ return block.newParser();
+ }
+ }
+ } catch (Exception e) {
+ final NotFoundException rnf = new NotFoundException("File " + file
+ + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id));
+ rnf.initCause(e);
+ throw rnf;
+ }
+ }
+
+ throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x"
+ + Integer.toHexString(id));
+ }
+
+ /**
+ * Start preloading of resource data using this Resources object. Only
+ * for use by the zygote process for loading common system resources.
+ * {@hide}
+ */
+ public final void startPreloading() {
+ synchronized (sSync) {
+ if (sPreloaded) {
+ throw new IllegalStateException("Resources already preloaded");
+ }
+ sPreloaded = true;
+ mPreloading = true;
+ mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE;
+ updateConfiguration(null, null, null);
+ }
+ }
+
+ /**
+ * Called by zygote when it is done preloading resources, to change back
+ * to normal Resources operation.
+ */
+ void finishPreloading() {
+ if (mPreloading) {
+ mPreloading = false;
+ flushLayoutCache();
+ }
+ }
+
+ LongSparseArray<Drawable.ConstantState> getPreloadedDrawables() {
+ return sPreloadedDrawables[0];
+ }
+
+ ThemeImpl newThemeImpl() {
+ return new ThemeImpl();
+ }
+
+ public class ThemeImpl {
+ /**
+ * Unique key for the series of styles applied to this theme.
+ */
+ private final Resources.ThemeKey mKey = new Resources.ThemeKey();
+
+ @SuppressWarnings("hiding")
+ private final AssetManager mAssets;
+ private final long mTheme;
+
+ /**
+ * Resource identifier for the theme.
+ */
+ private int mThemeResId = 0;
+
+ /*package*/ ThemeImpl() {
+ mAssets = ResourcesImpl.this.mAssets;
+ mTheme = mAssets.createTheme();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ mAssets.releaseTheme(mTheme);
+ }
+
+ /*package*/ Resources.ThemeKey getKey() {
+ return mKey;
+ }
+
+ /*package*/ long getNativeTheme() {
+ return mTheme;
+ }
+
+ /*package*/ int getAppliedStyleResId() {
+ return mThemeResId;
+ }
+
+ void applyStyle(int resId, boolean force) {
+ synchronized (mKey) {
+ AssetManager.applyThemeStyle(mTheme, resId, force);
+
+ mThemeResId = resId;
+ mKey.append(resId, force);
+ }
+ }
+
+ void setTo(ThemeImpl other) {
+ synchronized (mKey) {
+ synchronized (other.mKey) {
+ AssetManager.copyTheme(mTheme, other.mTheme);
+
+ mThemeResId = other.mThemeResId;
+ mKey.setTo(other.getKey());
+ }
+ }
+ }
+
+ @NonNull
+ TypedArray obtainStyledAttributes(@NonNull Resources.Theme wrapper,
+ AttributeSet set,
+ @StyleableRes int[] attrs,
+ @AttrRes int defStyleAttr,
+ @StyleRes int defStyleRes) {
+ synchronized (mKey) {
+ final int len = attrs.length;
+ final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
+
+ // XXX note that for now we only work with compiled XML files.
+ // To support generic XML files we will need to manually parse
+ // out the attributes from the XML file (applying type information
+ // contained in the resources and such).
+ final XmlBlock.Parser parser = (XmlBlock.Parser) set;
+ AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
+ parser != null ? parser.mParseState : 0,
+ attrs, array.mData, array.mIndices);
+ array.mTheme = wrapper;
+ array.mXml = parser;
+
+ return array;
+ }
+ }
+
+ @NonNull
+ TypedArray resolveAttributes(@NonNull Resources.Theme wrapper,
+ @NonNull int[] values,
+ @NonNull int[] attrs) {
+ synchronized (mKey) {
+ final int len = attrs.length;
+ if (values == null || len != values.length) {
+ throw new IllegalArgumentException(
+ "Base attribute values must the same length as attrs");
+ }
+
+ final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
+ AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
+ array.mTheme = wrapper;
+ array.mXml = null;
+ return array;
+ }
+ }
+
+ boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
+ synchronized (mKey) {
+ return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
+ }
+ }
+
+ int[] getAllAttributes() {
+ return mAssets.getStyleAttributes(getAppliedStyleResId());
+ }
+
+ int getChangingConfigurations() {
+ synchronized (mKey) {
+ final int nativeChangingConfig =
+ AssetManager.getThemeChangingConfigurations(mTheme);
+ return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
+ }
+ }
+
+ public void dump(int priority, String tag, String prefix) {
+ synchronized (mKey) {
+ AssetManager.dumpTheme(mTheme, priority, tag, prefix);
+ }
+ }
+
+ String[] getTheme() {
+ synchronized (mKey) {
+ final int N = mKey.mCount;
+ final String[] themes = new String[N * 2];
+ for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) {
+ final int resId = mKey.mResId[j];
+ final boolean forced = mKey.mForce[j];
+ try {
+ themes[i] = getResourceName(resId);
+ } catch (NotFoundException e) {
+ themes[i] = Integer.toHexString(i);
+ }
+ themes[i + 1] = forced ? "forced" : "not forced";
+ }
+ return themes;
+ }
+ }
+
+ /**
+ * Rebases the theme against the parent Resource object's current
+ * configuration by re-applying the styles passed to
+ * {@link #applyStyle(int, boolean)}.
+ */
+ void rebase() {
+ synchronized (mKey) {
+ AssetManager.clearTheme(mTheme);
+
+ // Reapply the same styles in the same order.
+ for (int i = 0; i < mKey.mCount; i++) {
+ final int resId = mKey.mResId[i];
+ final boolean force = mKey.mForce[i];
+ AssetManager.applyThemeStyle(mTheme, resId, force);
+ }
+ }
+ }
+ }
+}
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index da49b64..022bdfb 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -1206,8 +1206,8 @@
/*package*/ TypedArray(Resources resources, int[] data, int[] indices, int len) {
mResources = resources;
- mMetrics = mResources.mMetrics;
- mAssets = mResources.mAssets;
+ mMetrics = mResources.getDisplayMetrics();
+ mAssets = mResources.getAssets();
mData = data;
mIndices = indices;
mLength = len;
diff --git a/core/java/android/hardware/CameraInfo.aidl b/core/java/android/hardware/CameraInfo.aidl
deleted file mode 100644
index e21e694..0000000
--- a/core/java/android/hardware/CameraInfo.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware;
-
-/** @hide */
-parcelable CameraInfo;
diff --git a/core/java/android/hardware/ICamera.aidl b/core/java/android/hardware/ICamera.aidl
deleted file mode 100644
index d4f64f8..0000000
--- a/core/java/android/hardware/ICamera.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware;
-
-/** @hide */
-interface ICamera
-{
- /**
- * Keep up-to-date with frameworks/av/include/camera/ICamera.h
- */
- void disconnect();
-}
diff --git a/core/java/android/hardware/ICameraClient.aidl b/core/java/android/hardware/ICameraClient.aidl
deleted file mode 100644
index d7877b4..0000000
--- a/core/java/android/hardware/ICameraClient.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware;
-
-/** @hide */
-interface ICameraClient
-{
- /**
- * Keep up-to-date with frameworks/av/include/camera/ICameraClient.h
- */
- // TODO: consider implementing this.
-}
diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl
deleted file mode 100644
index 0b165cd..0000000
--- a/core/java/android/hardware/ICameraService.aidl
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware;
-
-import android.hardware.ICamera;
-import android.hardware.ICameraClient;
-import android.hardware.camera2.ICameraDeviceUser;
-import android.hardware.camera2.ICameraDeviceCallbacks;
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.utils.BinderHolder;
-import android.hardware.ICameraServiceListener;
-import android.hardware.CameraInfo;
-
-/**
- * Binder interface for the native camera service running in mediaserver.
- *
- * @hide
- */
-interface ICameraService
-{
- /**
- * Keep up-to-date with frameworks/av/include/camera/ICameraService.h
- */
- int getNumberOfCameras(int type);
-
- // rest of 'int' return values in this file are actually status_t
-
- int getCameraInfo(int cameraId, out CameraInfo info);
-
- int connect(ICameraClient client, int cameraId,
- String opPackageName,
- int clientUid,
- // Container for an ICamera object
- out BinderHolder device);
-
- int connectDevice(ICameraDeviceCallbacks callbacks, int cameraId,
- String opPackageName,
- int clientUid,
- // Container for an ICameraDeviceUser object
- out BinderHolder device);
-
- int addListener(ICameraServiceListener listener);
- int removeListener(ICameraServiceListener listener);
-
- int getCameraCharacteristics(int cameraId, out CameraMetadataNative info);
-
- /**
- * The java stubs for this method are not intended to be used. Please use
- * the native stub in frameworks/av/include/camera/ICameraService.h instead.
- * The BinderHolder output is being used as a placeholder, and will not be
- * well-formatted in the generated java method.
- */
- int getCameraVendorTagDescriptor(out BinderHolder desc);
-
- // Writes the camera1 parameters into a single-element array.
- int getLegacyParameters(int cameraId, out String[] parameters);
- // Determines if a particular API version is supported; see ICameraService.h for version defines
- int supportsCameraApi(int cameraId, int apiVersion);
-
- int connectLegacy(ICameraClient client, int cameraId,
- int halVersion,
- String opPackageName,
- int clientUid,
- // Container for an ICamera object
- out BinderHolder device);
-
- int setTorchMode(String CameraId, boolean enabled, IBinder clientBinder);
-
- /**
- * Notify the camera service of a system event. Should only be called from system_server.
- *
- * Callers require the android.permission.CAMERA_SEND_SYSTEM_EVENTS permission.
- */
- oneway void notifySystemEvent(int eventId, in int[] args);
-}
diff --git a/core/java/android/hardware/ICameraServiceListener.aidl b/core/java/android/hardware/ICameraServiceListener.aidl
deleted file mode 100644
index 49278b6..0000000
--- a/core/java/android/hardware/ICameraServiceListener.aidl
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware;
-
-/** @hide */
-interface ICameraServiceListener
-{
- /**
- * Keep up-to-date with frameworks/av/include/camera/ICameraServiceListener.h
- */
- void onStatusChanged(int status, int cameraId);
-
- void onTorchStatusChanged(int status, String cameraId);
-}
diff --git a/core/java/android/hardware/ICameraServiceProxy.aidl b/core/java/android/hardware/ICameraServiceProxy.aidl
deleted file mode 100644
index 0e654d5..0000000
--- a/core/java/android/hardware/ICameraServiceProxy.aidl
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware;
-
-/**
- * Binder interface for the camera service proxy running in system_server.
- *
- * Keep in sync with frameworks/av/include/camera/ICameraServiceProxy.h
- *
- * @hide
- */
-interface ICameraServiceProxy
-{
- /**
- * Ping the service proxy to update the valid users for the camera service.
- */
- oneway void pingForUserUpdate();
-
- /**
- * Update the status of a camera device
- */
- oneway void notifyCameraState(String cameraId, int newCameraState);
-}
diff --git a/core/java/android/hardware/camera2/CameraAccessException.java b/core/java/android/hardware/camera2/CameraAccessException.java
index 933ce0d..f9b659c 100644
--- a/core/java/android/hardware/camera2/CameraAccessException.java
+++ b/core/java/android/hardware/camera2/CameraAccessException.java
@@ -114,12 +114,12 @@
}
public CameraAccessException(@AccessError int problem, String message) {
- super(message);
+ super(getCombinedMessage(problem, message));
mReason = problem;
}
public CameraAccessException(@AccessError int problem, String message, Throwable cause) {
- super(message, cause);
+ super(getCombinedMessage(problem, message), cause);
mReason = problem;
}
@@ -151,4 +151,37 @@
}
return null;
}
+
+ private static String getCombinedMessage(@AccessError int problem, String message) {
+ String problemString = getProblemString(problem);
+ return String.format("%s (%d): %s", problemString, problem, message);
+ }
+
+ private static String getProblemString(int problem) {
+ String problemString;
+ switch (problem) {
+ case CAMERA_IN_USE:
+ problemString = "CAMERA_IN_USE";
+ break;
+ case MAX_CAMERAS_IN_USE:
+ problemString = "MAX_CAMERAS_IN_USE";
+ break;
+ case CAMERA_DISCONNECTED:
+ problemString = "CAMERA_DISCONNECTED";
+ break;
+ case CAMERA_DISABLED:
+ problemString = "CAMERA_DISABLED";
+ break;
+ case CAMERA_ERROR:
+ problemString = "CAMERA_ERROR";
+ break;
+ case CAMERA_DEPRECATED_HAL:
+ problemString = "CAMERA_DEPRECATED_HAL";
+ break;
+ default:
+ problemString = "<UNKNOWN ERROR>";
+ }
+ return problemString;
+ }
+
}
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 51796eb..b3c8e3b 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -26,15 +26,14 @@
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.legacy.CameraDeviceUserShim;
import android.hardware.camera2.legacy.LegacyMetadataMapper;
-import android.hardware.camera2.utils.CameraServiceBinderDecorator;
-import android.hardware.camera2.utils.CameraRuntimeException;
-import android.hardware.camera2.utils.BinderHolder;
import android.os.IBinder;
import android.os.Binder;
+import android.os.DeadObjectException;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
import android.util.Log;
import android.util.ArrayMap;
@@ -240,25 +239,19 @@
if (!supportsCamera2ApiLocked(cameraId)) {
// Legacy backwards compatibility path; build static info from the camera
// parameters
- String[] outParameters = new String[1];
+ String parameters = cameraService.getLegacyParameters(id);
- cameraService.getLegacyParameters(id, /*out*/outParameters);
- String parameters = outParameters[0];
-
- CameraInfo info = new CameraInfo();
- cameraService.getCameraInfo(id, /*out*/info);
+ CameraInfo info = cameraService.getCameraInfo(id);
characteristics = LegacyMetadataMapper.createCharacteristics(parameters, info);
} else {
// Normal path: Get the camera characteristics directly from the camera service
- CameraMetadataNative info = new CameraMetadataNative();
-
- cameraService.getCameraCharacteristics(id, info);
+ CameraMetadataNative info = cameraService.getCameraCharacteristics(id);
characteristics = new CameraCharacteristics(info);
}
- } catch (CameraRuntimeException e) {
- throw e.asChecked();
+ } catch (ServiceSpecificException e) {
+ throwAsPublicException(e);
} catch (RemoteException e) {
// Camera service died - act as if the camera was disconnected
throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
@@ -292,85 +285,83 @@
throws CameraAccessException {
CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
CameraDevice device = null;
- try {
- synchronized (mLock) {
+ synchronized (mLock) {
- ICameraDeviceUser cameraUser = null;
+ ICameraDeviceUser cameraUser = null;
- android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
- new android.hardware.camera2.impl.CameraDeviceImpl(
- cameraId,
- callback,
- handler,
- characteristics);
+ android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
+ new android.hardware.camera2.impl.CameraDeviceImpl(
+ cameraId,
+ callback,
+ handler,
+ characteristics);
- BinderHolder holder = new BinderHolder();
+ ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
- ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
- int id = Integer.parseInt(cameraId);
- try {
- if (supportsCamera2ApiLocked(cameraId)) {
- // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
- ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
- if (cameraService == null) {
- throw new CameraRuntimeException(
- CameraAccessException.CAMERA_DISCONNECTED,
- "Camera service is currently unavailable");
- }
- cameraService.connectDevice(callbacks, id,
- mContext.getOpPackageName(), USE_CALLING_UID, holder);
- cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
- } else {
- // Use legacy camera implementation for HAL1 devices
- Log.i(TAG, "Using legacy camera HAL.");
- cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
- }
- } catch (CameraRuntimeException e) {
- if (e.getReason() == CameraAccessException.CAMERA_DEPRECATED_HAL) {
- throw new AssertionError("Should've gone down the shim path");
- } else if (e.getReason() == CameraAccessException.CAMERA_IN_USE ||
- e.getReason() == CameraAccessException.MAX_CAMERAS_IN_USE ||
- e.getReason() == CameraAccessException.CAMERA_DISABLED ||
- e.getReason() == CameraAccessException.CAMERA_DISCONNECTED ||
- e.getReason() == CameraAccessException.CAMERA_ERROR) {
- // Received one of the known connection errors
- // The remote camera device cannot be connected to, so
- // set the local camera to the startup error state
- deviceImpl.setRemoteFailure(e);
-
- if (e.getReason() == CameraAccessException.CAMERA_DISABLED ||
- e.getReason() == CameraAccessException.CAMERA_DISCONNECTED ||
- e.getReason() == CameraAccessException.CAMERA_IN_USE) {
- // Per API docs, these failures call onError and throw
- throw e.asChecked();
- }
- } else {
- // Unexpected failure - rethrow
- throw e;
- }
- } catch (RemoteException e) {
- // Camera service died - act as if it's a CAMERA_DISCONNECTED case
- CameraRuntimeException ce = new CameraRuntimeException(
- CameraAccessException.CAMERA_DISCONNECTED,
- "Camera service is currently unavailable", e);
- deviceImpl.setRemoteFailure(ce);
- throw ce.asChecked();
- }
-
- // TODO: factor out callback to be non-nested, then move setter to constructor
- // For now, calling setRemoteDevice will fire initial
- // onOpened/onUnconfigured callbacks.
- deviceImpl.setRemoteDevice(cameraUser);
- device = deviceImpl;
+ int id;
+ try {
+ id = Integer.parseInt(cameraId);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
+ + cameraId);
}
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
- + cameraId);
- } catch (CameraRuntimeException e) {
- throw e.asChecked();
+ try {
+ if (supportsCamera2ApiLocked(cameraId)) {
+ // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
+ ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
+ if (cameraService == null) {
+ throw new ServiceSpecificException(
+ ICameraService.ERROR_DISCONNECTED,
+ "Camera service is currently unavailable");
+ }
+ cameraUser = cameraService.connectDevice(callbacks, id,
+ mContext.getOpPackageName(), USE_CALLING_UID);
+ } else {
+ // Use legacy camera implementation for HAL1 devices
+ Log.i(TAG, "Using legacy camera HAL.");
+ cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
+ }
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
+ throw new AssertionError("Should've gone down the shim path");
+ } else if (e.errorCode == ICameraService.ERROR_CAMERA_IN_USE ||
+ e.errorCode == ICameraService.ERROR_MAX_CAMERAS_IN_USE ||
+ e.errorCode == ICameraService.ERROR_DISABLED ||
+ e.errorCode == ICameraService.ERROR_DISCONNECTED ||
+ e.errorCode == ICameraService.ERROR_INVALID_OPERATION) {
+ // Received one of the known connection errors
+ // The remote camera device cannot be connected to, so
+ // set the local camera to the startup error state
+ deviceImpl.setRemoteFailure(e);
+
+ if (e.errorCode == ICameraService.ERROR_DISABLED ||
+ e.errorCode == ICameraService.ERROR_DISCONNECTED ||
+ e.errorCode == ICameraService.ERROR_CAMERA_IN_USE) {
+ // Per API docs, these failures call onError and throw
+ throwAsPublicException(e);
+ }
+ } else {
+ // Unexpected failure - rethrow
+ throwAsPublicException(e);
+ }
+ } catch (RemoteException e) {
+ // Camera service died - act as if it's a CAMERA_DISCONNECTED case
+ ServiceSpecificException sse = new ServiceSpecificException(
+ ICameraService.ERROR_DISCONNECTED,
+ "Camera service is currently unavailable");
+ deviceImpl.setRemoteFailure(sse);
+ throwAsPublicException(sse);
+ }
+
+ // TODO: factor out callback to be non-nested, then move setter to constructor
+ // For now, calling setRemoteDevice will fire initial
+ // onOpened/onUnconfigured callbacks.
+ deviceImpl.setRemoteDevice(cameraUser);
+ device = deviceImpl;
}
+
return device;
}
@@ -602,6 +593,56 @@
}
/**
+ * Convert ServiceSpecificExceptions and Binder RemoteExceptions from camera binder interfaces
+ * into the correct public exceptions.
+ *
+ * @hide
+ */
+ public static void throwAsPublicException(Throwable t) throws CameraAccessException {
+ if (t instanceof ServiceSpecificException) {
+ ServiceSpecificException e = (ServiceSpecificException) t;
+ int reason = CameraAccessException.CAMERA_ERROR;
+ switch(e.errorCode) {
+ case ICameraService.ERROR_DISCONNECTED:
+ reason = CameraAccessException.CAMERA_DISCONNECTED;
+ break;
+ case ICameraService.ERROR_DISABLED:
+ reason = CameraAccessException.CAMERA_DISABLED;
+ break;
+ case ICameraService.ERROR_CAMERA_IN_USE:
+ reason = CameraAccessException.CAMERA_IN_USE;
+ break;
+ case ICameraService.ERROR_MAX_CAMERAS_IN_USE:
+ reason = CameraAccessException.MAX_CAMERAS_IN_USE;
+ break;
+ case ICameraService.ERROR_DEPRECATED_HAL:
+ reason = CameraAccessException.CAMERA_DEPRECATED_HAL;
+ break;
+ case ICameraService.ERROR_ILLEGAL_ARGUMENT:
+ case ICameraService.ERROR_ALREADY_EXISTS:
+ throw new IllegalArgumentException(e.getMessage(), e);
+ case ICameraService.ERROR_PERMISSION_DENIED:
+ throw new SecurityException(e.getMessage(), e);
+ case ICameraService.ERROR_TIMED_OUT:
+ case ICameraService.ERROR_INVALID_OPERATION:
+ default:
+ reason = CameraAccessException.CAMERA_ERROR;
+ }
+ throw new CameraAccessException(reason, e.getMessage(), e);
+ } else if (t instanceof DeadObjectException) {
+ throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
+ "Camera service has died unexpectedly",
+ t);
+ } else if (t instanceof RemoteException) {
+ throw new UnsupportedOperationException("An unknown RemoteException was thrown" +
+ " which should never happen.", t);
+ } else if (t instanceof RuntimeException) {
+ RuntimeException e = (RuntimeException) t;
+ throw e;
+ }
+ }
+
+ /**
* Return or create the list of currently connected camera devices.
*
* <p>In case of errors connecting to the camera service, will return an empty list.</p>
@@ -619,34 +660,32 @@
try {
numCameras = cameraService.getNumberOfCameras(CAMERA_TYPE_ALL);
- } catch(CameraRuntimeException e) {
- throw e.asChecked();
+ } catch(ServiceSpecificException e) {
+ throwAsPublicException(e);
} catch (RemoteException e) {
// camera service just died - if no camera service, then no devices
return deviceIdList;
}
- CameraMetadataNative info = new CameraMetadataNative();
for (int i = 0; i < numCameras; ++i) {
// Non-removable cameras use integers starting at 0 for their
// identifiers
boolean isDeviceSupported = false;
try {
- cameraService.getCameraCharacteristics(i, info);
+ CameraMetadataNative info = cameraService.getCameraCharacteristics(i);
if (!info.isEmpty()) {
isDeviceSupported = true;
} else {
throw new AssertionError("Expected to get non-empty characteristics");
}
- } catch(IllegalArgumentException e) {
- // Got a BAD_VALUE from service, meaning that this
- // device is not supported.
- } catch(CameraRuntimeException e) {
+ } catch(ServiceSpecificException e) {
// DISCONNECTED means that the HAL reported an low-level error getting the
- // device info; skip listing the device. Other errors,
+ // device info; ILLEGAL_ARGUMENT means that this devices is not supported.
+ // Skip listing the device. Other errors,
// propagate exception onward
- if (e.getReason() != CameraAccessException.CAMERA_DISCONNECTED) {
- throw e.asChecked();
+ if (e.errorCode != ICameraService.ERROR_DISCONNECTED ||
+ e.errorCode != ICameraService.ERROR_ILLEGAL_ARGUMENT) {
+ throwAsPublicException(e);
}
} catch(RemoteException e) {
// Camera service died - no devices to list
@@ -699,17 +738,7 @@
// If no camera service, no support
if (cameraService == null) return false;
- int res = cameraService.supportsCameraApi(id, apiVersion);
-
- if (res != CameraServiceBinderDecorator.NO_ERROR) {
- throw new AssertionError("Unexpected value " + res);
- }
- return true;
- } catch (CameraRuntimeException e) {
- if (e.getReason() != CameraAccessException.CAMERA_DEPRECATED_HAL) {
- throw e;
- }
- // API level is not supported
+ return cameraService.supportsCameraApi(id, apiVersion);
} catch (RemoteException e) {
// Camera service is now down, no support for any API level
}
@@ -737,21 +766,6 @@
*/
private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
- // Keep up-to-date with ICameraServiceListener.h
-
- // Device physically unplugged
- public static final int STATUS_NOT_PRESENT = 0;
- // Device physically has been plugged in
- // and the camera can be used exclusively
- public static final int STATUS_PRESENT = 1;
- // Device physically has been plugged in
- // but it will not be connect-able until enumeration is complete
- public static final int STATUS_ENUMERATING = 2;
- // Camera is in use by another app and cannot be used exclusively
- public static final int STATUS_NOT_AVAILABLE = 0x80000000;
-
- // End enums shared with ICameraServiceListener.h
-
// Camera ID -> Status map
private final ArrayMap<String, Integer> mDeviceStatus = new ArrayMap<String, Integer>();
@@ -759,17 +773,6 @@
private final ArrayMap<AvailabilityCallback, Handler> mCallbackMap =
new ArrayMap<AvailabilityCallback, Handler>();
- // Keep up-to-date with ICameraServiceListener.h
-
- // torch mode has become not available to set via setTorchMode().
- public static final int TORCH_STATUS_NOT_AVAILABLE = 0;
- // torch mode is off and available to be turned on via setTorchMode().
- public static final int TORCH_STATUS_AVAILABLE_OFF = 1;
- // torch mode is on and available to be turned off via setTorchMode().
- public static final int TORCH_STATUS_AVAILABLE_ON = 2;
-
- // End enums shared with ICameraServiceListener.h
-
// torch client binder to set the torch mode with.
private Binder mTorchClientBinder = new Binder();
@@ -839,29 +842,20 @@
return;
}
- ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
-
- /**
- * Wrap the camera service in a decorator which automatically translates return codes
- * into exceptions.
- */
- ICameraService cameraService =
- CameraServiceBinderDecorator.newInstance(cameraServiceRaw);
+ ICameraService cameraService = ICameraService.Stub.asInterface(cameraServiceBinder);
try {
- CameraServiceBinderDecorator.throwOnError(
- CameraMetadataNative.nativeSetupGlobalVendorTagDescriptor());
- } catch (CameraRuntimeException e) {
- handleRecoverableSetupErrors(e, "Failed to set up vendor tags");
+ CameraMetadataNative.setupGlobalVendorTagDescriptor();
+ } catch (ServiceSpecificException e) {
+ handleRecoverableSetupErrors(e);
}
try {
cameraService.addListener(this);
mCameraService = cameraService;
- } catch(CameraRuntimeException e) {
+ } catch(ServiceSpecificException e) {
// Unexpected failure
- throw new IllegalStateException("Failed to register a camera service listener",
- e.asChecked());
+ throw new IllegalStateException("Failed to register a camera service listener", e);
} catch (RemoteException e) {
// Camera service is now down, leave mCameraService as null
}
@@ -881,16 +875,9 @@
}
try {
- int status = cameraService.setTorchMode(cameraId, enabled, mTorchClientBinder);
- } catch(CameraRuntimeException e) {
- int problem = e.getReason();
- switch (problem) {
- case CameraAccessException.CAMERA_ERROR:
- throw new IllegalArgumentException(
- "the camera device doesn't have a flash unit.");
- default:
- throw e.asChecked();
- }
+ cameraService.setTorchMode(cameraId, enabled, mTorchClientBinder);
+ } catch(ServiceSpecificException e) {
+ throwAsPublicException(e);
} catch (RemoteException e) {
throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
"Camera service is currently unavailable");
@@ -898,21 +885,19 @@
}
}
- private void handleRecoverableSetupErrors(CameraRuntimeException e, String msg) {
- int problem = e.getReason();
- switch (problem) {
- case CameraAccessException.CAMERA_DISCONNECTED:
- String errorMsg = CameraAccessException.getDefaultMessage(problem);
- Log.w(TAG, msg + ": " + errorMsg);
+ private void handleRecoverableSetupErrors(ServiceSpecificException e) {
+ switch (e.errorCode) {
+ case ICameraService.ERROR_DISCONNECTED:
+ Log.w(TAG, e.getMessage());
break;
default:
- throw new IllegalStateException(msg, e.asChecked());
+ throw new IllegalStateException(e);
}
}
private boolean isAvailable(int status) {
switch (status) {
- case STATUS_PRESENT:
+ case ICameraServiceListener.STATUS_PRESENT:
return true;
default:
return false;
@@ -921,10 +906,10 @@
private boolean validStatus(int status) {
switch (status) {
- case STATUS_NOT_PRESENT:
- case STATUS_PRESENT:
- case STATUS_ENUMERATING:
- case STATUS_NOT_AVAILABLE:
+ case ICameraServiceListener.STATUS_NOT_PRESENT:
+ case ICameraServiceListener.STATUS_PRESENT:
+ case ICameraServiceListener.STATUS_ENUMERATING:
+ case ICameraServiceListener.STATUS_NOT_AVAILABLE:
return true;
default:
return false;
@@ -933,9 +918,9 @@
private boolean validTorchStatus(int status) {
switch (status) {
- case TORCH_STATUS_NOT_AVAILABLE:
- case TORCH_STATUS_AVAILABLE_ON:
- case TORCH_STATUS_AVAILABLE_OFF:
+ case ICameraServiceListener.TORCH_STATUS_NOT_AVAILABLE:
+ case ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON:
+ case ICameraServiceListener.TORCH_STATUS_AVAILABLE_OFF:
return true;
default:
return false;
@@ -966,14 +951,14 @@
private void postSingleTorchUpdate(final TorchCallback callback, final Handler handler,
final String id, final int status) {
switch(status) {
- case TORCH_STATUS_AVAILABLE_ON:
- case TORCH_STATUS_AVAILABLE_OFF:
+ case ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON:
+ case ICameraServiceListener.TORCH_STATUS_AVAILABLE_OFF:
handler.post(
new Runnable() {
@Override
public void run() {
callback.onTorchModeChanged(id, status ==
- TORCH_STATUS_AVAILABLE_ON);
+ ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON);
}
});
break;
@@ -1220,11 +1205,12 @@
// and torch statuses will be updated.
for (int i = 0; i < mDeviceStatus.size(); i++) {
String cameraId = mDeviceStatus.keyAt(i);
- onStatusChangedLocked(STATUS_NOT_PRESENT, cameraId);
+ onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, cameraId);
}
for (int i = 0; i < mTorchStatus.size(); i++) {
String cameraId = mTorchStatus.keyAt(i);
- onTorchStatusChangedLocked(TORCH_STATUS_NOT_AVAILABLE, cameraId);
+ onTorchStatusChangedLocked(ICameraServiceListener.TORCH_STATUS_NOT_AVAILABLE,
+ cameraId);
}
scheduleCameraServiceReconnectionLocked();
diff --git a/core/java/android/hardware/camera2/CaptureRequest.aidl b/core/java/android/hardware/camera2/CaptureRequest.aidl
deleted file mode 100644
index 0b7d5ba..0000000
--- a/core/java/android/hardware/camera2/CaptureRequest.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2;
-
-/** @hide */
-parcelable CaptureRequest;
diff --git a/core/java/android/hardware/camera2/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java
index 57a080b..9478dc0 100644
--- a/core/java/android/hardware/camera2/DngCreator.java
+++ b/core/java/android/hardware/camera2/DngCreator.java
@@ -137,6 +137,11 @@
throw new IllegalArgumentException("Orientation " + orientation +
" is not a valid EXIF orientation value");
}
+ // ExifInterface and TIFF/EP spec differ on definition of
+ // "Unknown" orientation; other values map directly
+ if (orientation == ExifInterface.ORIENTATION_UNDEFINED) {
+ orientation = TAG_ORIENTATION_UNKNOWN;
+ }
nativeSetOrientation(orientation);
return this;
}
@@ -443,7 +448,7 @@
private static final String GPS_LONG_REF_WEST = "W";
private static final String GPS_DATE_FORMAT_STR = "yyyy:MM:dd";
- private static final String TIFF_DATETIME_FORMAT = "yyyy:MM:dd kk:mm:ss";
+ private static final String TIFF_DATETIME_FORMAT = "yyyy:MM:dd HH:mm:ss";
private static final DateFormat sExifGPSDateStamp = new SimpleDateFormat(GPS_DATE_FORMAT_STR);
private static final DateFormat sDateTimeStampFormat =
new SimpleDateFormat(TIFF_DATETIME_FORMAT);
@@ -458,6 +463,9 @@
private static final int DEFAULT_PIXEL_STRIDE = 2; // bytes per sample
private static final int BYTES_PER_RGB_PIX = 3; // byts per pixel
+ // TIFF tag values needed to map between public API and TIFF spec
+ private static final int TAG_ORIENTATION_UNKNOWN = 9;
+
/**
* Offset, rowStride, and pixelStride are given in bytes. Height and width are given in pixels.
*/
diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
deleted file mode 100644
index 151c918..0000000
--- a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2;
-
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.impl.CaptureResultExtras;
-
-/** @hide */
-interface ICameraDeviceCallbacks
-{
- /**
- * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
- */
-
- oneway void onDeviceError(int errorCode, in CaptureResultExtras resultExtras);
- oneway void onDeviceIdle();
- oneway void onCaptureStarted(in CaptureResultExtras resultExtras, long timestamp);
- oneway void onResultReceived(in CameraMetadataNative result,
- in CaptureResultExtras resultExtras);
- oneway void onPrepared(int streamId);
-}
diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
deleted file mode 100644
index c9c9abc..0000000
--- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2;
-
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.params.OutputConfiguration;
-import android.hardware.camera2.utils.LongParcelable;
-import android.view.Surface;
-
-/** @hide */
-interface ICameraDeviceUser
-{
- /**
- * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceUser.h and
- * frameworks/base/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
- */
- void disconnect();
-
- // ints here are status_t
-
- // non-negative value is the requestId. negative value is status_t
- int submitRequest(in CaptureRequest request, boolean streaming,
- out LongParcelable lastFrameNumber);
-
- int submitRequestList(in List<CaptureRequest> requestList, boolean streaming,
- out LongParcelable lastFrameNumber);
-
- int cancelRequest(int requestId, out LongParcelable lastFrameNumber);
-
- /**
- * Begin the device configuration.
- *
- * <p>
- * beginConfigure must be called before any call to deleteStream, createStream,
- * or endConfigure. It is not valid to call this when the device is not idle.
- * <p>
- */
- int beginConfigure();
-
- /**
- * End the device configuration.
- *
- * <p>
- * endConfigure must be called after stream configuration is complete (i.e. after
- * a call to beginConfigure and subsequent createStream/deleteStream calls). This
- * must be called before any requests can be submitted.
- * <p>
- */
- int endConfigure(boolean isConstrainedHighSpeed);
-
- int deleteStream(int streamId);
-
- // non-negative value is the stream ID. negative value is status_t
- int createStream(in OutputConfiguration outputConfiguration);
-
- /**
- * Create an input stream
- *
- * <p>Create an input stream of width, height, and format</p>
- *
- * @param width Width of the input buffers
- * @param height Height of the input buffers
- * @param format Format of the input buffers. One of HAL_PIXEL_FORMAT_*.
- *
- * @return stream ID if it's a non-negative value. status_t if it's a negative value.
- */
- int createInputStream(int width, int height, int format);
-
- /**
- * Get the surface of the input stream.
- *
- * <p>It's valid to call this method only after a stream configuration is completed
- * successfully and the stream configuration includes a input stream.</p>
- *
- * @param surface An output argument for the surface of the input stream buffer queue.
- */
- int getInputSurface(out Surface surface);
-
- int createDefaultRequest(int templateId, out CameraMetadataNative request);
-
- int getCameraInfo(out CameraMetadataNative info);
-
- int waitUntilIdle();
-
- int flush(out LongParcelable lastFrameNumber);
-
- int prepare(int streamId);
-
- int tearDown(int streamId);
-
- int prepare2(int maxCount, int streamId);
-}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 3aba0d1..00dd780 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -33,14 +33,14 @@
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.ReprocessFormatsMap;
import android.hardware.camera2.params.StreamConfigurationMap;
-import android.hardware.camera2.utils.CameraBinderDecorator;
-import android.hardware.camera2.utils.CameraRuntimeException;
-import android.hardware.camera2.utils.LongParcelable;
+import android.hardware.camera2.utils.SubmitInfo;
import android.hardware.camera2.utils.SurfaceUtils;
+import android.hardware.ICameraService;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.util.Log;
import android.util.Range;
import android.util.Size;
@@ -70,7 +70,7 @@
private static final int REQUEST_ID_NONE = -1;
// TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
- private ICameraDeviceUser mRemoteDevice;
+ private ICameraDeviceUserWrapper mRemoteDevice;
// Lock to synchronize cross-thread access to device public interface
final Object mInterfaceLock = new Object(); // access from this class and Session only!
@@ -267,7 +267,7 @@
// If setRemoteFailure already called, do nothing
if (mInError) return;
- mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
+ mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);
mDeviceHandler.post(mCallOnOpened);
mDeviceHandler.post(mCallOnUnconfigured);
@@ -280,28 +280,29 @@
* <p>This places the camera device in the error state and informs the callback.
* Use in place of setRemoteDevice() when startup fails.</p>
*/
- public void setRemoteFailure(final CameraRuntimeException failure) {
+ public void setRemoteFailure(final ServiceSpecificException failure) {
int failureCode = StateCallback.ERROR_CAMERA_DEVICE;
boolean failureIsError = true;
- switch (failure.getReason()) {
- case CameraAccessException.CAMERA_IN_USE:
+ switch (failure.errorCode) {
+ case ICameraService.ERROR_CAMERA_IN_USE:
failureCode = StateCallback.ERROR_CAMERA_IN_USE;
break;
- case CameraAccessException.MAX_CAMERAS_IN_USE:
+ case ICameraService.ERROR_MAX_CAMERAS_IN_USE:
failureCode = StateCallback.ERROR_MAX_CAMERAS_IN_USE;
break;
- case CameraAccessException.CAMERA_DISABLED:
+ case ICameraService.ERROR_DISABLED:
failureCode = StateCallback.ERROR_CAMERA_DISABLED;
break;
- case CameraAccessException.CAMERA_DISCONNECTED:
+ case ICameraService.ERROR_DISCONNECTED:
failureIsError = false;
break;
- case CameraAccessException.CAMERA_ERROR:
+ case ICameraService.ERROR_INVALID_OPERATION:
failureCode = StateCallback.ERROR_CAMERA_DEVICE;
break;
default:
- Log.wtf(TAG, "Unknown failure in opening camera device: " + failure.getReason());
+ Log.e(TAG, "Unexpected failure in opening camera device: " + failure.errorCode +
+ failure.getMessage());
break;
}
final int code = failureCode;
@@ -430,27 +431,20 @@
}
}
- try {
- mRemoteDevice.endConfigure(isConstrainedHighSpeed);
- }
- catch (IllegalArgumentException e) {
- // OK. camera service can reject stream config if it's not supported by HAL
- // This is only the result of a programmer misusing the camera2 api.
- Log.w(TAG, "Stream configuration failed");
- return false;
- }
+ mRemoteDevice.endConfigure(isConstrainedHighSpeed);
success = true;
- } catch (CameraRuntimeException e) {
- if (e.getReason() == CAMERA_IN_USE) {
- throw new IllegalStateException("The camera is currently busy." +
- " You must wait until the previous operation completes.");
- }
-
- throw e.asChecked();
- } catch (RemoteException e) {
- // impossible
+ } catch (IllegalArgumentException e) {
+ // OK. camera service can reject stream config if it's not supported by HAL
+ // This is only the result of a programmer misusing the camera2 api.
+ Log.w(TAG, "Stream configuration failed due to: " + e.getMessage());
return false;
+ } catch (CameraAccessException e) {
+ if (e.getReason() == CameraAccessException.CAMERA_IN_USE) {
+ throw new IllegalStateException("The camera is currently busy." +
+ " You must wait until the previous operation completes.", e);
+ }
+ throw e;
} finally {
if (success && outputs.size() > 0) {
mDeviceHandler.post(mCallOnIdle);
@@ -594,12 +588,7 @@
configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations,
isConstrainedHighSpeed);
if (configureSuccess == true && inputConfig != null) {
- input = new Surface();
- try {
- mRemoteDevice.getInputSurface(/*out*/input);
- } catch (CameraRuntimeException e) {
- e.asChecked();
- }
+ input = mRemoteDevice.getInputSurface();
}
} catch (CameraAccessException e) {
configureSuccess = false;
@@ -608,9 +597,6 @@
if (DEBUG) {
Log.v(TAG, "createCaptureSession - failed with exception ", e);
}
- } catch (RemoteException e) {
- // impossible
- return;
}
List<Surface> outSurfaces = new ArrayList<>(outputConfigurations.size());
@@ -655,16 +641,9 @@
synchronized(mInterfaceLock) {
checkIfCameraClosedOrInError();
- CameraMetadataNative templatedRequest = new CameraMetadataNative();
+ CameraMetadataNative templatedRequest = null;
- try {
- mRemoteDevice.createDefaultRequest(templateType, /*out*/templatedRequest);
- } catch (CameraRuntimeException e) {
- throw e.asChecked();
- } catch (RemoteException e) {
- // impossible
- return null;
- }
+ templatedRequest = mRemoteDevice.createDefaultRequest(templateType);
CaptureRequest.Builder builder = new CaptureRequest.Builder(
templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE);
@@ -701,14 +680,8 @@
if (streamId == -1) {
throw new IllegalArgumentException("Surface is not part of this session");
}
- try {
- mRemoteDevice.prepare(streamId);
- } catch (CameraRuntimeException e) {
- throw e.asChecked();
- } catch (RemoteException e) {
- // impossible
- return;
- }
+
+ mRemoteDevice.prepare(streamId);
}
}
@@ -728,14 +701,8 @@
if (streamId == -1) {
throw new IllegalArgumentException("Surface is not part of this session");
}
- try {
- mRemoteDevice.prepare2(maxCount, streamId);
- } catch (CameraRuntimeException e) {
- throw e.asChecked();
- } catch (RemoteException e) {
- // impossible
- return;
- }
+
+ mRemoteDevice.prepare2(maxCount, streamId);
}
}
@@ -753,14 +720,8 @@
if (streamId == -1) {
throw new IllegalArgumentException("Surface is not part of this session");
}
- try {
- mRemoteDevice.tearDown(streamId);
- } catch (CameraRuntimeException e) {
- throw e.asChecked();
- } catch (RemoteException e) {
- // impossible
- return;
- }
+
+ mRemoteDevice.tearDown(streamId);
}
}
@@ -875,45 +836,37 @@
synchronized(mInterfaceLock) {
checkIfCameraClosedOrInError();
- int requestId;
-
if (repeating) {
stopRepeating();
}
- LongParcelable lastFrameNumberRef = new LongParcelable();
- try {
- requestId = mRemoteDevice.submitRequestList(requestList, repeating,
- /*out*/lastFrameNumberRef);
- if (DEBUG) {
- Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
- }
- } catch (CameraRuntimeException e) {
- throw e.asChecked();
- } catch (RemoteException e) {
- // impossible
- return -1;
+ SubmitInfo requestInfo;
+
+ CaptureRequest[] requestArray = requestList.toArray(new CaptureRequest[requestList.size()]);
+ requestInfo = mRemoteDevice.submitRequestList(requestArray, repeating);
+ if (DEBUG) {
+ Log.v(TAG, "last frame number " + requestInfo.getLastFrameNumber());
}
if (callback != null) {
- mCaptureCallbackMap.put(requestId, new CaptureCallbackHolder(callback,
- requestList, handler, repeating, mNextSessionId - 1));
+ mCaptureCallbackMap.put(requestInfo.getRequestId(),
+ new CaptureCallbackHolder(
+ callback, requestList, handler, repeating, mNextSessionId - 1));
} else {
if (DEBUG) {
- Log.d(TAG, "Listen for request " + requestId + " is null");
+ Log.d(TAG, "Listen for request " + requestInfo.getRequestId() + " is null");
}
}
- long lastFrameNumber = lastFrameNumberRef.getNumber();
-
if (repeating) {
if (mRepeatingRequestId != REQUEST_ID_NONE) {
- checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
+ checkEarlyTriggerSequenceComplete(mRepeatingRequestId,
+ requestInfo.getLastFrameNumber());
}
- mRepeatingRequestId = requestId;
+ mRepeatingRequestId = requestInfo.getRequestId();
} else {
- mRequestLastFrameNumbersList.add(new RequestLastFrameNumbersHolder(requestList,
- requestId, lastFrameNumber));
+ mRequestLastFrameNumbersList.add(
+ new RequestLastFrameNumbersHolder(requestList, requestInfo));
}
if (mIdle) {
@@ -921,7 +874,7 @@
}
mIdle = false;
- return requestId;
+ return requestInfo.getRequestId();
}
}
@@ -949,19 +902,9 @@
int requestId = mRepeatingRequestId;
mRepeatingRequestId = REQUEST_ID_NONE;
- try {
- LongParcelable lastFrameNumberRef = new LongParcelable();
- mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
- long lastFrameNumber = lastFrameNumberRef.getNumber();
+ long lastFrameNumber = mRemoteDevice.cancelRequest(requestId);
- checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
-
- } catch (CameraRuntimeException e) {
- throw e.asChecked();
- } catch (RemoteException e) {
- // impossible
- return;
- }
+ checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
}
}
}
@@ -974,14 +917,8 @@
if (mRepeatingRequestId != REQUEST_ID_NONE) {
throw new IllegalStateException("Active repeating request ongoing");
}
- try {
- mRemoteDevice.waitUntilIdle();
- } catch (CameraRuntimeException e) {
- throw e.asChecked();
- } catch (RemoteException e) {
- // impossible
- return;
- }
+
+ mRemoteDevice.waitUntilIdle();
}
}
@@ -997,19 +934,11 @@
mDeviceHandler.post(mCallOnIdle);
return;
}
- try {
- LongParcelable lastFrameNumberRef = new LongParcelable();
- mRemoteDevice.flush(/*out*/lastFrameNumberRef);
- if (mRepeatingRequestId != REQUEST_ID_NONE) {
- long lastFrameNumber = lastFrameNumberRef.getNumber();
- checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
- mRepeatingRequestId = REQUEST_ID_NONE;
- }
- } catch (CameraRuntimeException e) {
- throw e.asChecked();
- } catch (RemoteException e) {
- // impossible
- return;
+
+ long lastFrameNumber = mRemoteDevice.flush();
+ if (mRepeatingRequestId != REQUEST_ID_NONE) {
+ checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
+ mRepeatingRequestId = REQUEST_ID_NONE;
}
}
}
@@ -1021,14 +950,8 @@
return;
}
- try {
- if (mRemoteDevice != null) {
- mRemoteDevice.disconnect();
- }
- } catch (CameraRuntimeException e) {
- Log.e(TAG, "Exception while closing: ", e.asChecked());
- } catch (RemoteException e) {
- // impossible
+ if (mRemoteDevice != null) {
+ mRemoteDevice.disconnect();
}
// Only want to fire the onClosed callback once;
@@ -1297,14 +1220,14 @@
* Create a request-last-frame-numbers holder with a list of requests, request ID, and
* the last frame number returned by camera service.
*/
- public RequestLastFrameNumbersHolder(List<CaptureRequest> requestList, int requestId,
- long lastFrameNumber) {
+ public RequestLastFrameNumbersHolder(List<CaptureRequest> requestList, SubmitInfo requestInfo) {
long lastRegularFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
long lastReprocessFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
- long frameNumber = lastFrameNumber;
+ long frameNumber = requestInfo.getLastFrameNumber();
- if (lastFrameNumber < requestList.size() - 1) {
- throw new IllegalArgumentException("lastFrameNumber: " + lastFrameNumber +
+ if (requestInfo.getLastFrameNumber() < requestList.size() - 1) {
+ throw new IllegalArgumentException(
+ "lastFrameNumber: " + requestInfo.getLastFrameNumber() +
" should be at least " + (requestList.size() - 1) + " for the number of " +
" requests in the list: " + requestList.size());
}
@@ -1330,7 +1253,7 @@
mLastRegularFrameNumber = lastRegularFrameNumber;
mLastReprocessFrameNumber = lastReprocessFrameNumber;
- mRequestId = requestId;
+ mRequestId = requestInfo.getRequestId();
}
/**
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl b/core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl
deleted file mode 100644
index 4a89129..0000000
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.impl;
-
-/** @hide */
-parcelable CameraMetadataNative;
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 12a2910..79eac26 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -58,6 +58,7 @@
import android.location.LocationManager;
import android.os.Parcelable;
import android.os.Parcel;
+import android.os.ServiceSpecificException;
import android.util.Log;
import android.util.Size;
@@ -363,13 +364,24 @@
* Set the global client-side vendor tag descriptor to allow use of vendor
* tags in camera applications.
*
- * @return int A native status_t value corresponding to one of the
- * {@link CameraBinderDecorator} integer constants.
- * @see CameraBinderDecorator#throwOnError
- *
+ * @throws ServiceSpecificException
* @hide
*/
- public static native int nativeSetupGlobalVendorTagDescriptor();
+ public static void setupGlobalVendorTagDescriptor() throws ServiceSpecificException {
+ int err = nativeSetupGlobalVendorTagDescriptor();
+ if (err != 0) {
+ throw new ServiceSpecificException(err, "Failure to set up global vendor tags");
+ }
+ }
+
+ /**
+ * Set the global client-side vendor tag descriptor to allow use of vendor
+ * tags in camera applications.
+ *
+ * @return int An error code corresponding to one of the
+ * {@link ICameraService} error constants, or 0 on success.
+ */
+ private static native int nativeSetupGlobalVendorTagDescriptor();
/**
* Set a camera metadata field to a value. The field definitions can be
diff --git a/core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl b/core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
deleted file mode 100644
index ebc812a..0000000
--- a/core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.impl;
-
-/** @hide */
-parcelable CaptureResultExtras;
diff --git a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
new file mode 100644
index 0000000..ddc3fd1
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.impl;
+
+import static android.hardware.camera2.CameraAccessException.CAMERA_DISABLED;
+import static android.hardware.camera2.CameraAccessException.CAMERA_DISCONNECTED;
+import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
+import static android.hardware.camera2.CameraAccessException.CAMERA_ERROR;
+import static android.hardware.camera2.CameraAccessException.MAX_CAMERAS_IN_USE;
+import static android.hardware.camera2.CameraAccessException.CAMERA_DEPRECATED_HAL;
+
+import android.hardware.ICameraService;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.utils.SubmitInfo;
+import android.os.RemoteException;
+import android.view.Surface;
+
+/**
+ * A wrapper around ICameraDeviceUser.
+ *
+ * Mainly used to convert ServiceSpecificExceptions to the correct
+ * checked / unchecked exception.
+ *
+ * @hide
+ */
+public class ICameraDeviceUserWrapper {
+
+ private final ICameraDeviceUser mRemoteDevice;
+
+ public ICameraDeviceUserWrapper(ICameraDeviceUser remoteDevice) {
+ if (remoteDevice == null) {
+ throw new NullPointerException("Remote device may not be null");
+ }
+ mRemoteDevice = remoteDevice;
+ }
+
+ public void disconnect() {
+ try {
+ mRemoteDevice.disconnect();
+ } catch (RemoteException t) {
+ // ignore binder errors for disconnect
+ }
+ }
+
+ public SubmitInfo submitRequest(CaptureRequest request, boolean streaming)
+ throws CameraAccessException {
+ try {
+ return mRemoteDevice.submitRequest(request, streaming);
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
+ public SubmitInfo submitRequestList(CaptureRequest[] requestList, boolean streaming)
+ throws CameraAccessException {
+ try {
+ return mRemoteDevice.submitRequestList(requestList, streaming);
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
+ public long cancelRequest(int requestId) throws CameraAccessException {
+ try {
+ return mRemoteDevice.cancelRequest(requestId);
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
+ public void beginConfigure() throws CameraAccessException {
+ try {
+ mRemoteDevice.beginConfigure();
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
+ public void endConfigure(boolean isConstrainedHighSpeed) throws CameraAccessException {
+ try {
+ mRemoteDevice.endConfigure(isConstrainedHighSpeed);
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
+ public void deleteStream(int streamId) throws CameraAccessException {
+ try {
+ mRemoteDevice.deleteStream(streamId);
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
+ public int createStream(OutputConfiguration outputConfiguration)
+ throws CameraAccessException {
+ try {
+ return mRemoteDevice.createStream(outputConfiguration);
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
+ public int createInputStream(int width, int height, int format) throws CameraAccessException {
+ try {
+ return mRemoteDevice.createInputStream(width, height, format);
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
+ public Surface getInputSurface() throws CameraAccessException {
+ try {
+ return mRemoteDevice.getInputSurface();
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
+ public CameraMetadataNative createDefaultRequest(int templateId) throws CameraAccessException {
+ try {
+ return mRemoteDevice.createDefaultRequest(templateId);
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
+ public CameraMetadataNative getCameraInfo() throws CameraAccessException {
+ try {
+ return mRemoteDevice.getCameraInfo();
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
+ public void waitUntilIdle() throws CameraAccessException {
+ try {
+ mRemoteDevice.waitUntilIdle();
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
+ public long flush() throws CameraAccessException {
+ try {
+ return mRemoteDevice.flush();
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
+ public void prepare(int streamId) throws CameraAccessException {
+ try {
+ mRemoteDevice.prepare(streamId);
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
+ public void tearDown(int streamId) throws CameraAccessException {
+ try {
+ mRemoteDevice.tearDown(streamId);
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
+ public void prepare2(int maxCount, int streamId) throws CameraAccessException {
+ try {
+ mRemoteDevice.prepare2(maxCount, streamId);
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
+
+}
diff --git a/core/java/android/hardware/camera2/legacy/BurstHolder.java b/core/java/android/hardware/camera2/legacy/BurstHolder.java
index e7b3682..23efe15 100644
--- a/core/java/android/hardware/camera2/legacy/BurstHolder.java
+++ b/core/java/android/hardware/camera2/legacy/BurstHolder.java
@@ -35,10 +35,10 @@
*
* @param requestId id of the burst request.
* @param repeating true if this burst is repeating.
- * @param requests a {@link List} of {@link CaptureRequest}s in this burst.
+ * @param requests the array of {@link CaptureRequest}s for this burst.
* @param jpegSurfaceIds a {@link Collection} of IDs for the surfaces that have jpeg outputs.
*/
- public BurstHolder(int requestId, boolean repeating, List<CaptureRequest> requests,
+ public BurstHolder(int requestId, boolean repeating, CaptureRequest[] requests,
Collection<Long> jpegSurfaceIds) {
mRequestBuilders = new ArrayList<>();
int i = 0;
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index 798c941..d01c275 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -16,6 +16,7 @@
package android.hardware.camera2.legacy;
+import android.hardware.ICameraService;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.camera2.CameraAccessException;
@@ -23,12 +24,10 @@
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
-import android.hardware.camera2.utils.LongParcelable;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.impl.CaptureResultExtras;
import android.hardware.camera2.params.OutputConfiguration;
-import android.hardware.camera2.utils.CameraBinderDecorator;
-import android.hardware.camera2.utils.CameraRuntimeException;
+import android.hardware.camera2.utils.SubmitInfo;
import android.os.ConditionVariable;
import android.os.IBinder;
import android.os.Looper;
@@ -36,6 +35,7 @@
import android.os.HandlerThread;
import android.os.Message;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.util.Log;
import android.util.SparseArray;
import android.view.Surface;
@@ -93,7 +93,7 @@
private static int translateErrorsFromCamera1(int errorCode) {
if (errorCode == -EACCES) {
- return CameraBinderDecorator.PERMISSION_DENIED;
+ return ICameraService.ERROR_PERMISSION_DENIED;
}
return errorCode;
@@ -173,7 +173,7 @@
*
* @return int error code
*
- * @throws CameraRuntimeException if the camera open times out with ({@code CAMERA_ERROR})
+ * @throws ServiceSpecificException if the camera open times out with ({@code CAMERA_ERROR})
*/
public int waitForOpen(int timeoutMs) {
// Block until the camera is open asynchronously
@@ -186,7 +186,7 @@
Log.e(TAG, "connectBinderShim - Failed to release camera after timeout ", e);
}
- throw new CameraRuntimeException(CameraAccessException.CAMERA_ERROR);
+ throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION);
}
return mInitErrors;
@@ -344,7 +344,7 @@
Camera legacyCamera = init.getCamera();
// Check errors old HAL initialization
- CameraBinderDecorator.throwOnError(initErrors);
+ LegacyExceptionUtils.throwOnServiceError(initErrors);
// Disable shutter sounds (this will work unconditionally) for api2 clients
legacyCamera.disableShutterSound();
@@ -356,8 +356,8 @@
try {
legacyParameters = legacyCamera.getParameters();
} catch (RuntimeException e) {
- throw new CameraRuntimeException(CameraAccessException.CAMERA_ERROR,
- "Unable to get initial parameters", e);
+ throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION,
+ "Unable to get initial parameters: " + e.getMessage());
}
CameraCharacteristics characteristics =
@@ -386,101 +386,106 @@
}
@Override
- public int submitRequest(CaptureRequest request, boolean streaming,
- /*out*/LongParcelable lastFrameNumber) {
+ public SubmitInfo submitRequest(CaptureRequest request, boolean streaming) {
if (DEBUG) {
Log.d(TAG, "submitRequest called.");
}
if (mLegacyDevice.isClosed()) {
- Log.e(TAG, "Cannot submit request, device has been closed.");
- return -ENODEV;
+ String err = "Cannot submit request, device has been closed.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
synchronized(mConfigureLock) {
if (mConfiguring) {
- Log.e(TAG, "Cannot submit request, configuration change in progress.");
- return CameraBinderDecorator.INVALID_OPERATION;
+ String err = "Cannot submit request, configuration change in progress.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
}
- return mLegacyDevice.submitRequest(request, streaming, lastFrameNumber);
+ return mLegacyDevice.submitRequest(request, streaming);
}
@Override
- public int submitRequestList(List<CaptureRequest> request, boolean streaming,
- /*out*/LongParcelable lastFrameNumber) {
+ public SubmitInfo submitRequestList(CaptureRequest[] request, boolean streaming) {
if (DEBUG) {
Log.d(TAG, "submitRequestList called.");
}
if (mLegacyDevice.isClosed()) {
- Log.e(TAG, "Cannot submit request list, device has been closed.");
- return -ENODEV;
+ String err = "Cannot submit request list, device has been closed.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
synchronized(mConfigureLock) {
if (mConfiguring) {
- Log.e(TAG, "Cannot submit request, configuration change in progress.");
- return CameraBinderDecorator.INVALID_OPERATION;
+ String err = "Cannot submit request, configuration change in progress.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
}
- return mLegacyDevice.submitRequestList(request, streaming, lastFrameNumber);
+ return mLegacyDevice.submitRequestList(request, streaming);
}
@Override
- public int cancelRequest(int requestId, /*out*/LongParcelable lastFrameNumber) {
+ public long cancelRequest(int requestId) {
if (DEBUG) {
Log.d(TAG, "cancelRequest called.");
}
if (mLegacyDevice.isClosed()) {
- Log.e(TAG, "Cannot cancel request, device has been closed.");
- return -ENODEV;
+ String err = "Cannot cancel request, device has been closed.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
synchronized(mConfigureLock) {
if (mConfiguring) {
- Log.e(TAG, "Cannot cancel request, configuration change in progress.");
- return CameraBinderDecorator.INVALID_OPERATION;
+ String err = "Cannot cancel request, configuration change in progress.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
}
- long lastFrame = mLegacyDevice.cancelRequest(requestId);
- lastFrameNumber.setNumber(lastFrame);
- return CameraBinderDecorator.NO_ERROR;
+ return mLegacyDevice.cancelRequest(requestId);
}
@Override
- public int beginConfigure() {
+ public void beginConfigure() {
if (DEBUG) {
Log.d(TAG, "beginConfigure called.");
}
if (mLegacyDevice.isClosed()) {
- Log.e(TAG, "Cannot begin configure, device has been closed.");
- return -ENODEV;
+ String err = "Cannot begin configure, device has been closed.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
synchronized(mConfigureLock) {
if (mConfiguring) {
- Log.e(TAG, "Cannot begin configure, configuration change already in progress.");
- return CameraBinderDecorator.INVALID_OPERATION;
+ String err = "Cannot begin configure, configuration change already in progress.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
mConfiguring = true;
}
- return CameraBinderDecorator.NO_ERROR;
}
@Override
- public int endConfigure(boolean isConstrainedHighSpeed) {
+ public void endConfigure(boolean isConstrainedHighSpeed) {
if (DEBUG) {
Log.d(TAG, "endConfigure called.");
}
if (mLegacyDevice.isClosed()) {
- Log.e(TAG, "Cannot end configure, device has been closed.");
- return -ENODEV;
+ String err = "Cannot end configure, device has been closed.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
ArrayList<Surface> surfaces = null;
synchronized(mConfigureLock) {
if (!mConfiguring) {
- Log.e(TAG, "Cannot end configure, no configuration change in progress.");
- return CameraBinderDecorator.INVALID_OPERATION;
+ String err = "Cannot end configure, no configuration change in progress.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
int numSurfaces = mSurfaces.size();
if (numSurfaces > 0) {
@@ -491,32 +496,34 @@
}
mConfiguring = false;
}
- return mLegacyDevice.configureOutputs(surfaces);
+ mLegacyDevice.configureOutputs(surfaces);
}
@Override
- public int deleteStream(int streamId) {
+ public void deleteStream(int streamId) {
if (DEBUG) {
Log.d(TAG, "deleteStream called.");
}
if (mLegacyDevice.isClosed()) {
- Log.e(TAG, "Cannot delete stream, device has been closed.");
- return -ENODEV;
+ String err = "Cannot delete stream, device has been closed.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
synchronized(mConfigureLock) {
if (!mConfiguring) {
- Log.e(TAG, "Cannot delete stream, beginConfigure hasn't been called yet.");
- return CameraBinderDecorator.INVALID_OPERATION;
+ String err = "Cannot delete stream, no configuration change in progress.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
int index = mSurfaces.indexOfKey(streamId);
if (index < 0) {
- Log.e(TAG, "Cannot delete stream, stream id " + streamId + " doesn't exist.");
- return CameraBinderDecorator.BAD_VALUE;
+ String err = "Cannot delete stream, stream id " + streamId + " doesn't exist.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
}
mSurfaces.removeAt(index);
}
- return CameraBinderDecorator.NO_ERROR;
}
@Override
@@ -525,18 +532,21 @@
Log.d(TAG, "createStream called.");
}
if (mLegacyDevice.isClosed()) {
- Log.e(TAG, "Cannot create stream, device has been closed.");
- return -ENODEV;
+ String err = "Cannot create stream, device has been closed.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
synchronized(mConfigureLock) {
if (!mConfiguring) {
- Log.e(TAG, "Cannot create stream, beginConfigure hasn't been called yet.");
- return CameraBinderDecorator.INVALID_OPERATION;
+ String err = "Cannot create stream, beginConfigure hasn't been called yet.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
if (outputConfiguration.getRotation() != OutputConfiguration.ROTATION_0) {
- Log.e(TAG, "Cannot create stream, stream rotation is not supported.");
- return CameraBinderDecorator.INVALID_OPERATION;
+ String err = "Cannot create stream, stream rotation is not supported.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
}
int id = ++mSurfaceIdCounter;
mSurfaces.put(id, outputConfiguration.getSurface());
@@ -546,24 +556,27 @@
@Override
public int createInputStream(int width, int height, int format) {
- Log.e(TAG, "creating input stream is not supported on legacy devices");
- return CameraBinderDecorator.INVALID_OPERATION;
+ String err = "Creating input stream is not supported on legacy devices";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
@Override
- public int getInputSurface(/*out*/ Surface surface) {
- Log.e(TAG, "getting input surface is not supported on legacy devices");
- return CameraBinderDecorator.INVALID_OPERATION;
+ public Surface getInputSurface() {
+ String err = "Getting input surface is not supported on legacy devices";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
@Override
- public int createDefaultRequest(int templateId, /*out*/CameraMetadataNative request) {
+ public CameraMetadataNative createDefaultRequest(int templateId) {
if (DEBUG) {
Log.d(TAG, "createDefaultRequest called.");
}
if (mLegacyDevice.isClosed()) {
- Log.e(TAG, "Cannot create default request, device has been closed.");
- return -ENODEV;
+ String err = "Cannot create default request, device has been closed.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
CameraMetadataNative template;
@@ -571,99 +584,96 @@
template =
LegacyMetadataMapper.createRequestTemplate(mCameraCharacteristics, templateId);
} catch (IllegalArgumentException e) {
- Log.e(TAG, "createDefaultRequest - invalid templateId specified");
- return CameraBinderDecorator.BAD_VALUE;
+ String err = "createDefaultRequest - invalid templateId specified";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
}
- request.swap(template);
- return CameraBinderDecorator.NO_ERROR;
+ return template;
}
@Override
- public int getCameraInfo(/*out*/CameraMetadataNative info) {
+ public CameraMetadataNative getCameraInfo() {
if (DEBUG) {
Log.d(TAG, "getCameraInfo called.");
}
// TODO: implement getCameraInfo.
Log.e(TAG, "getCameraInfo unimplemented.");
- return CameraBinderDecorator.NO_ERROR;
+ return null;
}
@Override
- public int waitUntilIdle() throws RemoteException {
+ public void waitUntilIdle() throws RemoteException {
if (DEBUG) {
Log.d(TAG, "waitUntilIdle called.");
}
if (mLegacyDevice.isClosed()) {
- Log.e(TAG, "Cannot wait until idle, device has been closed.");
- return -ENODEV;
+ String err = "Cannot wait until idle, device has been closed.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
synchronized(mConfigureLock) {
if (mConfiguring) {
- Log.e(TAG, "Cannot wait until idle, configuration change in progress.");
- return CameraBinderDecorator.INVALID_OPERATION;
+ String err = "Cannot wait until idle, configuration change in progress.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
}
mLegacyDevice.waitUntilIdle();
- return CameraBinderDecorator.NO_ERROR;
}
@Override
- public int flush(/*out*/LongParcelable lastFrameNumber) {
+ public long flush() {
if (DEBUG) {
Log.d(TAG, "flush called.");
}
if (mLegacyDevice.isClosed()) {
- Log.e(TAG, "Cannot flush, device has been closed.");
- return -ENODEV;
+ String err = "Cannot flush, device has been closed.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
synchronized(mConfigureLock) {
if (mConfiguring) {
- Log.e(TAG, "Cannot flush, configuration change in progress.");
- return CameraBinderDecorator.INVALID_OPERATION;
+ String err = "Cannot flush, configuration change in progress.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
}
- long lastFrame = mLegacyDevice.flush();
- if (lastFrameNumber != null) {
- lastFrameNumber.setNumber(lastFrame);
- }
- return CameraBinderDecorator.NO_ERROR;
+ return mLegacyDevice.flush();
}
- public int prepare(int streamId) {
+ public void prepare(int streamId) {
if (DEBUG) {
Log.d(TAG, "prepare called.");
}
if (mLegacyDevice.isClosed()) {
- Log.e(TAG, "Cannot prepare stream, device has been closed.");
- return -ENODEV;
+ String err = "Cannot prepare stream, device has been closed.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
// LEGACY doesn't support actual prepare, just signal success right away
mCameraCallbacks.onPrepared(streamId);
-
- return CameraBinderDecorator.NO_ERROR;
}
- public int prepare2(int maxCount, int streamId) {
+ public void prepare2(int maxCount, int streamId) {
// We don't support this in LEGACY mode.
- return prepare(streamId);
+ prepare(streamId);
}
- public int tearDown(int streamId) {
+ public void tearDown(int streamId) {
if (DEBUG) {
Log.d(TAG, "tearDown called.");
}
if (mLegacyDevice.isClosed()) {
- Log.e(TAG, "Cannot tear down stream, device has been closed.");
- return -ENODEV;
+ String err = "Cannot tear down stream, device has been closed.";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
// LEGACY doesn't support actual teardown, so just a no-op
-
- return CameraBinderDecorator.NO_ERROR;
}
@Override
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index fddfbde..4c4adea 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -26,14 +26,13 @@
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.utils.ArrayUtils;
-import android.hardware.camera2.utils.CameraBinderDecorator;
-import android.hardware.camera2.utils.LongParcelable;
+import android.hardware.camera2.utils.SubmitInfo;
import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.utils.CameraRuntimeException;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.util.Log;
import android.util.Pair;
import android.util.Size;
@@ -45,7 +44,6 @@
import java.util.List;
import static android.hardware.camera2.legacy.LegacyExceptionUtils.*;
-import static android.hardware.camera2.utils.CameraBinderDecorator.*;
import static com.android.internal.util.Preconditions.*;
/**
@@ -357,9 +355,9 @@
if (success) {
mConfiguredSurfaces = outputs != null ? new ArrayList<>(outputs) : null;
} else {
- return CameraBinderDecorator.INVALID_OPERATION;
+ return LegacyExceptionUtils.INVALID_OPERATION;
}
- return CameraBinderDecorator.NO_ERROR;
+ return LegacyExceptionUtils.NO_ERROR;
}
/**
@@ -367,17 +365,16 @@
*
* @param requestList a list of capture requests to execute.
* @param repeating {@code true} if this burst is repeating.
- * @param frameNumber an output argument that contains either the frame number of the last frame
- * that will be returned for this request, or the frame number of the last
- * frame that will be returned for the current repeating request if this
- * burst is set to be repeating.
- * @return the request id.
+ * @return the submission info, including the new request id, and the last frame number, which
+ * contains either the frame number of the last frame that will be returned for this request,
+ * or the frame number of the last frame that will be returned for the current repeating
+ * request if this burst is set to be repeating.
*/
- public int submitRequestList(List<CaptureRequest> requestList, boolean repeating,
- /*out*/LongParcelable frameNumber) {
- if (requestList == null || requestList.isEmpty()) {
+ public SubmitInfo submitRequestList(CaptureRequest[] requestList, boolean repeating) {
+ if (requestList == null || requestList.length == 0) {
Log.e(TAG, "submitRequestList - Empty/null requests are not allowed");
- return BAD_VALUE;
+ throw new ServiceSpecificException(BAD_VALUE,
+ "submitRequestList - Empty/null requests are not allowed");
}
List<Long> surfaceIds = (mConfiguredSurfaces == null) ? new ArrayList<Long>() :
@@ -388,28 +385,33 @@
if (request.getTargets().isEmpty()) {
Log.e(TAG, "submitRequestList - "
+ "Each request must have at least one Surface target");
- return BAD_VALUE;
+ throw new ServiceSpecificException(BAD_VALUE,
+ "submitRequestList - "
+ + "Each request must have at least one Surface target");
}
for (Surface surface : request.getTargets()) {
if (surface == null) {
Log.e(TAG, "submitRequestList - Null Surface targets are not allowed");
- return BAD_VALUE;
+ throw new ServiceSpecificException(BAD_VALUE,
+ "submitRequestList - Null Surface targets are not allowed");
} else if (mConfiguredSurfaces == null) {
Log.e(TAG, "submitRequestList - must configure " +
" device with valid surfaces before submitting requests");
- return INVALID_OPERATION;
+ throw new ServiceSpecificException(INVALID_OPERATION,
+ "submitRequestList - must configure " +
+ " device with valid surfaces before submitting requests");
} else if (!containsSurfaceId(surface, surfaceIds)) {
Log.e(TAG, "submitRequestList - cannot use a surface that wasn't configured");
- return BAD_VALUE;
+ throw new ServiceSpecificException(BAD_VALUE,
+ "submitRequestList - cannot use a surface that wasn't configured");
}
}
}
// TODO: further validation of request here
mIdle.close();
- return mRequestThreadManager.submitCaptureRequests(requestList, repeating,
- frameNumber);
+ return mRequestThreadManager.submitCaptureRequests(requestList, repeating);
}
/**
@@ -417,17 +419,14 @@
*
* @param request the capture request to execute.
* @param repeating {@code true} if this request is repeating.
- * @param frameNumber an output argument that contains either the frame number of the last frame
- * that will be returned for this request, or the frame number of the last
- * frame that will be returned for the current repeating request if this
- * request is set to be repeating.
- * @return the request id.
+ * @return the submission info, including the new request id, and the last frame number, which
+ * contains either the frame number of the last frame that will be returned for this request,
+ * or the frame number of the last frame that will be returned for the current repeating
+ * request if this burst is set to be repeating.
*/
- public int submitRequest(CaptureRequest request, boolean repeating,
- /*out*/LongParcelable frameNumber) {
- ArrayList<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
- requestList.add(request);
- return submitRequestList(requestList, repeating, frameNumber);
+ public SubmitInfo submitRequest(CaptureRequest request, boolean repeating) {
+ CaptureRequest[] requestList = { request };
+ return submitRequestList(requestList, repeating);
}
/**
@@ -493,7 +492,7 @@
protected void finalize() throws Throwable {
try {
close();
- } catch (CameraRuntimeException e) {
+ } catch (ServiceSpecificException e) {
Log.e(TAG, "Got error while trying to finalize, ignoring: " + e.getMessage());
} finally {
super.finalize();
@@ -615,14 +614,16 @@
return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDataspace(surface));
}
- static void configureSurface(Surface surface, int width, int height,
- int pixelFormat) throws BufferQueueAbandonedException {
+ static void connectSurface(Surface surface) throws BufferQueueAbandonedException {
checkNotNull(surface);
- checkArgumentPositive(width, "width must be positive.");
- checkArgumentPositive(height, "height must be positive.");
- LegacyExceptionUtils.throwOnError(nativeConfigureSurface(surface, width, height,
- pixelFormat));
+ LegacyExceptionUtils.throwOnError(nativeConnectSurface(surface));
+ }
+
+ static void disconnectSurface(Surface surface) throws BufferQueueAbandonedException {
+ if (surface == null) return;
+
+ LegacyExceptionUtils.throwOnError(nativeDisconnectSurface(surface));
}
static void produceFrame(Surface surface, byte[] pixelBuffer, int width,
@@ -717,8 +718,7 @@
private static native int nativeDetectSurfaceDimens(Surface surface,
/*out*/int[/*2*/] dimens);
- private static native int nativeConfigureSurface(Surface surface, int width, int height,
- int pixelFormat);
+ private static native int nativeConnectSurface(Surface surface);
private static native int nativeProduceFrame(Surface surface, byte[] pixelBuffer, int width,
int height, int pixelFormat);
@@ -741,5 +741,7 @@
private static native int nativeSetScalingMode(Surface surface, int scalingMode);
+ private static native int nativeDisconnectSurface(Surface surface);
+
static native int nativeGetJpegFooterSize();
}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java b/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
index 4501e81..93d6001 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
@@ -16,10 +16,11 @@
package android.hardware.camera2.legacy;
-import android.hardware.camera2.utils.CameraBinderDecorator;
+import android.hardware.ICameraService;
+import android.os.ServiceSpecificException;
import android.util.AndroidException;
-import static android.system.OsConstants.ENODEV;
+import static android.system.OsConstants.*;
/**
* Utility class containing exception handling used solely by the compatibility mode shim.
@@ -27,6 +28,14 @@
public class LegacyExceptionUtils {
private static final String TAG = "LegacyExceptionUtils";
+ public static final int NO_ERROR = 0;
+ public static final int PERMISSION_DENIED = -EPERM;
+ public static final int ALREADY_EXISTS = -EEXIST;
+ public static final int BAD_VALUE = -EINVAL;
+ public static final int DEAD_OBJECT = -ENOSYS;
+ public static final int INVALID_OPERATION = -EPIPE;
+ public static final int TIMED_OUT = -ETIMEDOUT;
+
/**
* Checked exception thrown when a BufferQueue has been abandoned by its consumer.
*/
@@ -58,8 +67,8 @@
* @return {@code errorFlag} if the value was non-negative, throws otherwise.
*/
public static int throwOnError(int errorFlag) throws BufferQueueAbandonedException {
- if (errorFlag == CameraBinderDecorator.NO_ERROR) {
- return CameraBinderDecorator.NO_ERROR;
+ if (errorFlag == NO_ERROR) {
+ return NO_ERROR;
} else if (errorFlag == -ENODEV) {
throw new BufferQueueAbandonedException();
}
@@ -70,6 +79,59 @@
return errorFlag;
}
+ /**
+ * Throw error codes returned by the camera service as exceptions.
+ *
+ * @param errorFlag error to throw as an exception.
+ */
+ public static void throwOnServiceError(int errorFlag) {
+ int errorCode = ICameraService.ERROR_INVALID_OPERATION;
+ String errorMsg;
+
+ if (errorFlag >= NO_ERROR) {
+ return;
+ } else if (errorFlag == PERMISSION_DENIED) {
+ errorCode = ICameraService.ERROR_PERMISSION_DENIED;
+ errorMsg = "Lacking privileges to access camera service";
+ } else if (errorFlag == ALREADY_EXISTS) {
+ // This should be handled at the call site. Typically this isn't bad,
+ // just means we tried to do an operation that already completed.
+ return;
+ } else if (errorFlag == BAD_VALUE) {
+ errorCode = ICameraService.ERROR_ILLEGAL_ARGUMENT;
+ errorMsg = "Bad argument passed to camera service";
+ } else if (errorFlag == DEAD_OBJECT) {
+ errorCode = ICameraService.ERROR_DISCONNECTED;
+ errorMsg = "Camera service not available";
+ } else if (errorFlag == TIMED_OUT) {
+ errorCode = ICameraService.ERROR_INVALID_OPERATION;
+ errorMsg = "Operation timed out in camera service";
+ } else if (errorFlag == -EACCES) {
+ errorCode = ICameraService.ERROR_DISABLED;
+ errorMsg = "Camera disabled by policy";
+ } else if (errorFlag == -EBUSY) {
+ errorCode = ICameraService.ERROR_CAMERA_IN_USE;
+ errorMsg = "Camera already in use";
+ } else if (errorFlag == -EUSERS) {
+ errorCode = ICameraService.ERROR_MAX_CAMERAS_IN_USE;
+ errorMsg = "Maximum number of cameras in use";
+ } else if (errorFlag == -ENODEV) {
+ errorCode = ICameraService.ERROR_DISCONNECTED;
+ errorMsg = "Camera device not available";
+ } else if (errorFlag == -EOPNOTSUPP) {
+ errorCode = ICameraService.ERROR_DEPRECATED_HAL;
+ errorMsg = "Deprecated camera HAL does not support this";
+ } else if (errorFlag == INVALID_OPERATION) {
+ errorCode = ICameraService.ERROR_INVALID_OPERATION;
+ errorMsg = "Illegal state encountered in camera service.";
+ } else {
+ errorCode = ICameraService.ERROR_INVALID_OPERATION;
+ errorMsg = "Unknown camera device error " + errorFlag;
+ }
+
+ throw new ServiceSpecificException(errorCode, errorMsg);
+ }
+
private LegacyExceptionUtils() {
throw new AssertionError();
}
diff --git a/core/java/android/hardware/camera2/legacy/RequestQueue.java b/core/java/android/hardware/camera2/legacy/RequestQueue.java
index c995029..8f252a1 100644
--- a/core/java/android/hardware/camera2/legacy/RequestQueue.java
+++ b/core/java/android/hardware/camera2/legacy/RequestQueue.java
@@ -16,7 +16,7 @@
package android.hardware.camera2.legacy;
import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.utils.LongParcelable;
+import android.hardware.camera2.utils.SubmitInfo;
import android.util.Log;
import android.util.Pair;
@@ -111,31 +111,29 @@
*
* @param requests the burst of requests to add to the queue.
* @param repeating true if the burst is repeating.
- * @param frameNumber an output argument that contains either the frame number of the last frame
- * that will be returned for this request, or the frame number of the last
- * frame that will be returned for the current repeating request if this
- * burst is set to be repeating.
- * @return the request id.
+ * @return the submission info, including the new request id, and the last frame number, which
+ * contains either the frame number of the last frame that will be returned for this request,
+ * or the frame number of the last frame that will be returned for the current repeating
+ * request if this burst is set to be repeating.
*/
- public synchronized int submit(List<CaptureRequest> requests, boolean repeating,
- /*out*/LongParcelable frameNumber) {
+ public synchronized SubmitInfo submit(CaptureRequest[] requests, boolean repeating) {
int requestId = mCurrentRequestId++;
BurstHolder burst = new BurstHolder(requestId, repeating, requests, mJpegSurfaceIds);
- long ret = INVALID_FRAME;
+ long lastFrame = INVALID_FRAME;
if (burst.isRepeating()) {
Log.i(TAG, "Repeating capture request set.");
if (mRepeatingRequest != null) {
- ret = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME :
+ lastFrame = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME :
mCurrentRepeatingFrameNumber - 1;
}
mCurrentRepeatingFrameNumber = INVALID_FRAME;
mRepeatingRequest = burst;
} else {
mRequestQueue.offer(burst);
- ret = calculateLastFrame(burst.getRequestId());
+ lastFrame = calculateLastFrame(burst.getRequestId());
}
- frameNumber.setNumber(ret);
- return requestId;
+ SubmitInfo info = new SubmitInfo(requestId, lastFrame);
+ return info;
}
private long calculateLastFrame(int requestId) {
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index 4866598..e8ce3ec 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -21,7 +21,7 @@
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.impl.CameraDeviceImpl;
-import android.hardware.camera2.utils.LongParcelable;
+import android.hardware.camera2.utils.SubmitInfo;
import android.hardware.camera2.utils.SizeAreaComparator;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.os.ConditionVariable;
@@ -365,6 +365,14 @@
mGLThreadManager.waitUntilIdle();
}
resetJpegSurfaceFormats(mCallbackOutputs);
+
+ for (Surface s : mCallbackOutputs) {
+ try {
+ LegacyCameraDevice.disconnectSurface(s);
+ } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+ Log.w(TAG, "Surface abandoned, skipping...", e);
+ }
+ }
mPreviewOutputs.clear();
mCallbackOutputs.clear();
mJpegSurfaceIds.clear();
@@ -392,6 +400,10 @@
mJpegSurfaceIds.add(LegacyCameraDevice.getSurfaceId(s));
mCallbackOutputs.add(s);
callbackOutputSizes.add(outSize);
+
+ // LegacyCameraDevice is the producer of JPEG output surfaces
+ // so LegacyCameraDevice needs to connect to the surfaces.
+ LegacyCameraDevice.connectSurface(s);
break;
default:
LegacyCameraDevice.setScalingMode(s, LegacyCameraDevice.
@@ -1008,21 +1020,19 @@
*
* @param requests the burst of requests to add to the queue.
* @param repeating true if the burst is repeating.
- * @param frameNumber an output argument that contains either the frame number of the last frame
- * that will be returned for this request, or the frame number of the last
- * frame that will be returned for the current repeating request if this
- * burst is set to be repeating.
- * @return the request id.
+ * @return the submission info, including the new request id, and the last frame number, which
+ * contains either the frame number of the last frame that will be returned for this request,
+ * or the frame number of the last frame that will be returned for the current repeating
+ * request if this burst is set to be repeating.
*/
- public int submitCaptureRequests(List<CaptureRequest> requests, boolean repeating,
- /*out*/LongParcelable frameNumber) {
+ public SubmitInfo submitCaptureRequests(CaptureRequest[] requests, boolean repeating) {
Handler handler = mRequestThread.waitAndGetHandler();
- int ret;
+ SubmitInfo info;
synchronized (mIdleLock) {
- ret = mRequestQueue.submit(requests, repeating, frameNumber);
+ info = mRequestQueue.submit(requests, repeating);
handler.sendEmptyMessage(MSG_SUBMIT_CAPTURE_REQUEST);
}
- return ret;
+ return info;
}
/**
diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
index bc80fc1..70bc2fd 100644
--- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
+++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
@@ -401,6 +401,13 @@
private void clearState() {
mSurfaces.clear();
+ for (EGLSurfaceHolder holder : mConversionSurfaces) {
+ try {
+ LegacyCameraDevice.disconnectSurface(holder.surface);
+ } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+ Log.w(TAG, "Surface abandoned, skipping...", e);
+ }
+ }
mConversionSurfaces.clear();
mPBufferPixels = null;
if (mSurfaceTexture != null) {
@@ -631,6 +638,9 @@
holder.height = surfaceSize.getHeight();
if (LegacyCameraDevice.needsConversion(s)) {
mConversionSurfaces.add(holder);
+ // LegacyCameraDevice is the producer of surfaces if it's not handled by EGL,
+ // so LegacyCameraDevice needs to connect to the surfaces.
+ LegacyCameraDevice.connectSurface(s);
} else {
mSurfaces.add(holder);
}
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.aidl b/core/java/android/hardware/camera2/params/OutputConfiguration.aidl
deleted file mode 100644
index 0921cd8..0000000
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.params;
-
-/** @hide */
-parcelable OutputConfiguration;
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 4407e55..cd0c474 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -21,11 +21,11 @@
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.utils.HashCodeHelpers;
import android.hardware.camera2.utils.SurfaceUtils;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
-import android.os.Parcel;
-import android.os.Parcelable;
import static com.android.internal.util.Preconditions.*;
diff --git a/core/java/android/hardware/camera2/params/VendorTagDescriptor.java b/core/java/android/hardware/camera2/params/VendorTagDescriptor.java
new file mode 100644
index 0000000..ea424e5
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/VendorTagDescriptor.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.params;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * A class for describing the vendor tags declared by a camera HAL module.
+ * Generally only used by the native side of
+ * android.hardware.camera2.impl.CameraMetadataNative
+ *
+ * @hide
+ */
+public final class VendorTagDescriptor implements Parcelable {
+
+ private VendorTagDescriptor(Parcel source) {
+ }
+
+ public static final Parcelable.Creator<VendorTagDescriptor> CREATOR =
+ new Parcelable.Creator<VendorTagDescriptor>() {
+ @Override
+ public VendorTagDescriptor createFromParcel(Parcel source) {
+ try {
+ VendorTagDescriptor vendorDescriptor = new VendorTagDescriptor(source);
+ return vendorDescriptor;
+ } catch (Exception e) {
+ Log.e(TAG, "Exception creating VendorTagDescriptor from parcel", e);
+ return null;
+ }
+ }
+
+ @Override
+ public VendorTagDescriptor[] newArray(int size) {
+ return new VendorTagDescriptor[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ if (dest == null) {
+ throw new IllegalArgumentException("dest must not be null");
+ }
+ }
+
+ private static final String TAG = "VendorTagDescriptor";
+}
diff --git a/core/java/android/hardware/camera2/utils/BinderHolder.aidl b/core/java/android/hardware/camera2/utils/BinderHolder.aidl
deleted file mode 100644
index f39d645..0000000
--- a/core/java/android/hardware/camera2/utils/BinderHolder.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.utils;
-
-/** @hide */
-parcelable BinderHolder;
diff --git a/core/java/android/hardware/camera2/utils/BinderHolder.java b/core/java/android/hardware/camera2/utils/BinderHolder.java
deleted file mode 100644
index 9eea390..0000000
--- a/core/java/android/hardware/camera2/utils/BinderHolder.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.utils;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.IBinder;
-
-/**
- * @hide
- */
-public class BinderHolder implements Parcelable {
- private IBinder mBinder = null;
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeStrongBinder(mBinder);
- }
-
- public void readFromParcel(Parcel src) {
- mBinder = src.readStrongBinder();
- }
-
- public static final Parcelable.Creator<BinderHolder> CREATOR =
- new Parcelable.Creator<BinderHolder>() {
- @Override
- public BinderHolder createFromParcel(Parcel in) {
- return new BinderHolder(in);
- }
-
- @Override
- public BinderHolder[] newArray(int size) {
- return new BinderHolder[size];
- }
- };
-
- public IBinder getBinder() {
- return mBinder;
- }
-
- public void setBinder(IBinder binder) {
- mBinder = binder;
- }
-
- public BinderHolder() {}
-
- public BinderHolder(IBinder binder) {
- mBinder = binder;
- }
-
- private BinderHolder(Parcel in) {
- mBinder = in.readStrongBinder();
- }
-}
-
diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
deleted file mode 100644
index 162edc9..0000000
--- a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.utils;
-
-import static android.hardware.camera2.CameraAccessException.CAMERA_DISABLED;
-import static android.hardware.camera2.CameraAccessException.CAMERA_DISCONNECTED;
-import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
-import static android.hardware.camera2.CameraAccessException.CAMERA_ERROR;
-import static android.hardware.camera2.CameraAccessException.MAX_CAMERAS_IN_USE;
-import static android.hardware.camera2.CameraAccessException.CAMERA_DEPRECATED_HAL;
-import static android.system.OsConstants.*;
-
-import android.os.DeadObjectException;
-import android.os.RemoteException;
-
-import java.lang.reflect.Method;
-
-/**
- * Translate camera device status_t return values into exceptions.
- *
- * @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance
- * @hide
- */
-public class CameraBinderDecorator {
-
- public static final int NO_ERROR = 0;
- public static final int PERMISSION_DENIED = -EPERM;
- public static final int ALREADY_EXISTS = -EEXIST;
- public static final int BAD_VALUE = -EINVAL;
- public static final int DEAD_OBJECT = -ENOSYS;
- public static final int INVALID_OPERATION = -EPIPE;
- public static final int TIMED_OUT = -ETIMEDOUT;
-
- /**
- * TODO: add as error codes in Errors.h
- * - POLICY_PROHIBITS
- * - RESOURCE_BUSY
- * - NO_SUCH_DEVICE
- * - NOT_SUPPORTED
- * - TOO_MANY_USERS
- */
-
- static class CameraBinderDecoratorListener implements Decorator.DecoratorListener {
-
- @Override
- public void onBeforeInvocation(Method m, Object[] args) {
- }
-
- @Override
- public void onAfterInvocation(Method m, Object[] args, Object result) {
- // int return type => status_t => convert to exception
- if (m.getReturnType() == Integer.TYPE) {
- int returnValue = (Integer) result;
- throwOnError(returnValue);
- }
- }
-
- @Override
- public boolean onCatchException(Method m, Object[] args, Throwable t) {
-
- if (t instanceof DeadObjectException) {
- throw new CameraRuntimeException(CAMERA_DISCONNECTED,
- "Process hosting the camera service has died unexpectedly",
- t);
- } else if (t instanceof RemoteException) {
- throw new UnsupportedOperationException("An unknown RemoteException was thrown" +
- " which should never happen.", t);
- }
-
- return false;
- }
-
- @Override
- public void onFinally(Method m, Object[] args) {
- }
-
- }
-
- /**
- * Throw error codes returned by the camera service as exceptions.
- *
- * @param errorFlag error to throw as an exception.
- */
- public static void throwOnError(int errorFlag) {
- if (errorFlag == NO_ERROR) {
- return;
- } else if (errorFlag == PERMISSION_DENIED) {
- throw new SecurityException("Lacking privileges to access camera service");
- } else if (errorFlag == ALREADY_EXISTS) {
- // This should be handled at the call site. Typically this isn't bad,
- // just means we tried to do an operation that already completed.
- return;
- } else if (errorFlag == BAD_VALUE) {
- throw new IllegalArgumentException("Bad argument passed to camera service");
- } else if (errorFlag == DEAD_OBJECT) {
- throw new CameraRuntimeException(CAMERA_DISCONNECTED);
- } else if (errorFlag == TIMED_OUT) {
- throw new CameraRuntimeException(CAMERA_ERROR,
- "Operation timed out in camera service");
- } else if (errorFlag == -EACCES) {
- throw new CameraRuntimeException(CAMERA_DISABLED);
- } else if (errorFlag == -EBUSY) {
- throw new CameraRuntimeException(CAMERA_IN_USE);
- } else if (errorFlag == -EUSERS) {
- throw new CameraRuntimeException(MAX_CAMERAS_IN_USE);
- } else if (errorFlag == -ENODEV) {
- throw new CameraRuntimeException(CAMERA_DISCONNECTED);
- } else if (errorFlag == -EOPNOTSUPP) {
- throw new CameraRuntimeException(CAMERA_DEPRECATED_HAL);
- } else if (errorFlag == INVALID_OPERATION) {
- throw new CameraRuntimeException(CAMERA_ERROR,
- "Illegal state encountered in camera service.");
- }
-
- /**
- * Trap the rest of the negative return values. If we have known
- * error codes i.e. ALREADY_EXISTS that aren't really runtime
- * errors, then add them to the top switch statement
- */
- if (errorFlag < 0) {
- throw new CameraRuntimeException(CAMERA_ERROR,
- String.format("Unknown camera device error %d", errorFlag));
- }
- }
-
- /**
- * <p>
- * Wraps the type T with a proxy that will check 'status_t' return codes
- * from the native side of the camera service, and throw Java exceptions
- * automatically based on the code.
- * </p>
- * <p>
- * In addition it also rewrites binder's RemoteException into either a
- * CameraAccessException or an UnsupportedOperationException.
- * </p>
- * <p>
- * As a result of calling any method on the proxy, RemoteException is
- * guaranteed never to be thrown.
- * </p>
- *
- * @param obj object that will serve as the target for all method calls
- * @param <T> the type of the element you want to wrap. This must be an interface.
- * @return a proxy that will intercept all invocations to obj
- */
- public static <T> T newInstance(T obj) {
- return Decorator.<T> newInstance(obj, new CameraBinderDecoratorListener());
- }
-}
diff --git a/core/java/android/hardware/camera2/utils/CameraRuntimeException.java b/core/java/android/hardware/camera2/utils/CameraRuntimeException.java
deleted file mode 100644
index 9ed88a9..0000000
--- a/core/java/android/hardware/camera2/utils/CameraRuntimeException.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package android.hardware.camera2.utils;
-
-import android.hardware.camera2.CameraAccessException;
-
-/**
- * @hide
- */
-public class CameraRuntimeException extends RuntimeException {
-
- private final int mReason;
- private String mMessage;
- private Throwable mCause;
-
- public final int getReason() {
- return mReason;
- }
-
- public CameraRuntimeException(int problem) {
- super();
- mReason = problem;
- }
-
- public CameraRuntimeException(int problem, String message) {
- super(message);
- mReason = problem;
- mMessage = message;
- }
-
- public CameraRuntimeException(int problem, String message, Throwable cause) {
- super(message, cause);
- mReason = problem;
- mMessage = message;
- mCause = cause;
- }
-
- public CameraRuntimeException(int problem, Throwable cause) {
- super(cause);
- mReason = problem;
- mCause = cause;
- }
-
- /**
- * Recreate this exception as the CameraAccessException equivalent.
- * @return CameraAccessException
- */
- public CameraAccessException asChecked() {
- CameraAccessException e;
-
- if (mMessage != null && mCause != null) {
- e = new CameraAccessException(mReason, mMessage, mCause);
- } else if (mMessage != null) {
- e = new CameraAccessException(mReason, mMessage);
- } else if (mCause != null) {
- e = new CameraAccessException(mReason, mCause);
- } else {
- e = new CameraAccessException(mReason);
- }
- // throw and catch, so java has a chance to fill out the stack trace
- e.setStackTrace(this.getStackTrace());
-
- return e;
- }
-}
diff --git a/core/java/android/hardware/camera2/utils/CameraServiceBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraServiceBinderDecorator.java
deleted file mode 100644
index c1fb6b1..0000000
--- a/core/java/android/hardware/camera2/utils/CameraServiceBinderDecorator.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.utils;
-
-import android.os.DeadObjectException;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.lang.reflect.Method;
-
-/**
- * Translate camera service status_t return values into exceptions.
- *
- * @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance
- * @hide
- */
-public class CameraServiceBinderDecorator extends CameraBinderDecorator {
-
- private static final String TAG = "CameraServiceBinderDecorator";
-
- static class CameraServiceBinderDecoratorListener
- extends CameraBinderDecorator.CameraBinderDecoratorListener {
-
- // Pass through remote exceptions, unlike CameraBinderDecorator
- @Override
- public boolean onCatchException(Method m, Object[] args, Throwable t) {
-
- if (t instanceof DeadObjectException) {
- // Can sometimes happen (camera service died)
- // Pass on silently
- } else if (t instanceof RemoteException) {
- // Some other kind of remote exception - this is not normal, so let's at least
- // note it before moving on
- Log.e(TAG, "Unexpected RemoteException from camera service call.", t);
- }
- // All other exceptions also get sent onward
- return false;
- }
-
- }
-
- /**
- * <p>
- * Wraps the type T with a proxy that will check 'status_t' return codes
- * from the native side of the camera service, and throw Java exceptions
- * automatically based on the code.
- * </p>
- *
- * @param obj object that will serve as the target for all method calls
- * @param <T> the type of the element you want to wrap. This must be an interface.
- * @return a proxy that will intercept all invocations to obj
- */
- public static <T> T newInstance(T obj) {
- return Decorator.<T> newInstance(obj, new CameraServiceBinderDecoratorListener());
- }
-}
diff --git a/core/java/android/hardware/camera2/utils/Decorator.java b/core/java/android/hardware/camera2/utils/Decorator.java
deleted file mode 100644
index 5826497..0000000
--- a/core/java/android/hardware/camera2/utils/Decorator.java
+++ /dev/null
@@ -1,92 +0,0 @@
-
-package android.hardware.camera2.utils;
-
-import java.lang.reflect.*;
-
-/**
- * This is an implementation of the 'decorator' design pattern using Java's proxy mechanism.
- *
- * @see android.hardware.camera2.utils.Decorator#newInstance
- *
- * @hide
- */
-public class Decorator<T> implements InvocationHandler {
-
- public interface DecoratorListener {
- /**
- * This method is called before the target method is invoked
- * @param args arguments to target method
- * @param m Method being called
- */
- void onBeforeInvocation(Method m, Object[] args);
- /**
- * This function is called after the target method is invoked
- * if there were no uncaught exceptions
- * @param args arguments to target method
- * @param m Method being called
- * @param result return value of target method
- */
- void onAfterInvocation(Method m, Object[] args, Object result);
- /**
- * This method is called only if there was an exception thrown by the target method
- * during its invocation.
- *
- * @param args arguments to target method
- * @param m Method being called
- * @param t Throwable that was thrown
- * @return false to rethrow exception, true if the exception was handled
- */
- boolean onCatchException(Method m, Object[] args, Throwable t);
- /**
- * This is called after the target method is invoked, regardless of whether or not
- * there were any exceptions.
- * @param args arguments to target method
- * @param m Method being called
- */
- void onFinally(Method m, Object[] args);
- }
-
- private final T mObject;
- private final DecoratorListener mListener;
-
- /**
- * Create a decorator wrapping the specified object's method calls.
- *
- * @param obj the object whose method calls you want to intercept
- * @param listener the decorator handler for intercepted method calls
- * @param <T> the type of the element you want to wrap. This must be an interface.
- * @return a wrapped interface-compatible T
- */
- @SuppressWarnings("unchecked")
- public static<T> T newInstance(T obj, DecoratorListener listener) {
- return (T)java.lang.reflect.Proxy.newProxyInstance(
- obj.getClass().getClassLoader(),
- obj.getClass().getInterfaces(),
- new Decorator<T>(obj, listener));
- }
-
- private Decorator(T obj, DecoratorListener listener) {
- this.mObject = obj;
- this.mListener = listener;
- }
-
- @Override
- public Object invoke(Object proxy, Method m, Object[] args)
- throws Throwable
- {
- Object result = null;
- try {
- mListener.onBeforeInvocation(m, args);
- result = m.invoke(mObject, args);
- mListener.onAfterInvocation(m, args, result);
- } catch (InvocationTargetException e) {
- Throwable t = e.getTargetException();
- if (!mListener.onCatchException(m, args, t)) {
- throw t;
- }
- } finally {
- mListener.onFinally(m, args);
- }
- return result;
- }
-}
diff --git a/core/java/android/hardware/camera2/utils/SubmitInfo.java b/core/java/android/hardware/camera2/utils/SubmitInfo.java
new file mode 100644
index 0000000..d1692b5
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/SubmitInfo.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.utils;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.hardware.camera2.ICameraDeviceUser;
+
+/**
+ * The status information returned for a successful capture request submission.
+ *
+ * Includes the request ID for the newly submitted capture request, and the
+ * last frame number of either the previous repeating request (for repeating
+ * requests), or of the request(s) just submitted (for single-shot capture).
+ *
+ * @hide
+ */
+public class SubmitInfo implements Parcelable {
+
+ private int mRequestId;
+ private long mLastFrameNumber;
+
+ public SubmitInfo() {
+ mRequestId = -1;
+ mLastFrameNumber = ICameraDeviceUser.NO_IN_FLIGHT_REPEATING_FRAMES;
+ }
+
+ public SubmitInfo(int requestId, long lastFrameNumber) {
+ mRequestId = requestId;
+ mLastFrameNumber = lastFrameNumber;
+ }
+
+ public static final Parcelable.Creator<SubmitInfo> CREATOR =
+ new Parcelable.Creator<SubmitInfo>() {
+ @Override
+ public SubmitInfo createFromParcel(Parcel in) {
+ return new SubmitInfo(in);
+ }
+
+ @Override
+ public SubmitInfo[] newArray(int size) {
+ return new SubmitInfo[size];
+ }
+ };
+
+ private SubmitInfo(Parcel in) {
+ readFromParcel(in);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mRequestId);
+ dest.writeLong(mLastFrameNumber);
+ }
+
+ public void readFromParcel(Parcel in) {
+ mRequestId = in.readInt();
+ mLastFrameNumber = in.readLong();
+ }
+
+ /**
+ * Return the request ID for the submitted capture request/burst.
+ *
+ * This is used to track the completion status of the requested captures,
+ * and to cancel repeating requests.
+ */
+ public int getRequestId() {
+ return mRequestId;
+ }
+
+ /**
+ * Return the last frame number for the submitted capture request/burst.
+ *
+ * For a repeating request, this is the last frame number of the _prior_
+ * repeating request, to indicate when to fire the sequence completion callback
+ * for the prior repeating request.
+ *
+ * For a single-shot capture, this is the last frame number of _this_
+ * burst, to indicate when to fire the sequence completion callback for the request itself.
+ *
+ * For a repeating request, may be NO_IN_FLIGHT_REPEATING_FRAMES, if no
+ * instances of a prior repeating request were actually issued to the camera device.
+ */
+ public long getLastFrameNumber() {
+ return mLastFrameNumber;
+ }
+
+}
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index cc2b764..b635088 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -689,12 +689,19 @@
return false;
if (triggerInData != other.triggerInData)
return false;
- if (captureFormat.getSampleRate() != other.captureFormat.getSampleRate())
- return false;
- if (captureFormat.getEncoding() != other.captureFormat.getEncoding())
- return false;
- if (captureFormat.getChannelMask() != other.captureFormat.getChannelMask())
- return false;
+ if (captureFormat == null) {
+ if (other.captureFormat != null)
+ return false;
+ } else {
+ if (other.captureFormat == null)
+ return false;
+ if (captureFormat.getSampleRate() != other.captureFormat.getSampleRate())
+ return false;
+ if (captureFormat.getEncoding() != other.captureFormat.getEncoding())
+ return false;
+ if (captureFormat.getChannelMask() != other.captureFormat.getChannelMask())
+ return false;
+ }
return true;
}
@@ -1002,10 +1009,10 @@
int encoding = in.readInt();
int channelMask = in.readInt();
captureFormat = (new AudioFormat.Builder())
- .setChannelMask(channelMask)
- .setEncoding(encoding)
- .setSampleRate(sampleRate)
- .build();
+ .setChannelMask(channelMask)
+ .setEncoding(encoding)
+ .setSampleRate(sampleRate)
+ .build();
}
byte[] data = in.readBlob();
KeyphraseRecognitionExtra[] keyphraseExtras =
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 20c2168..9e360e1 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -200,6 +200,14 @@
*/
public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15;
+ /**
+ * Sent by ConnectivityService to the NetworkAgent to install an APF program in the network
+ * chipset for use to filter packets.
+ *
+ * obj = byte[] containing the APF program bytecode.
+ */
+ public static final int CMD_PUSH_APF_PROGRAM = BASE + 16;
+
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score) {
this(looper, context, logTag, ni, nc, lp, score, null);
@@ -319,6 +327,10 @@
preventAutomaticReconnect();
break;
}
+ case CMD_PUSH_APF_PROGRAM: {
+ installPacketFilter((byte[]) msg.obj);
+ break;
+ }
}
}
@@ -494,6 +506,15 @@
protected void preventAutomaticReconnect() {
}
+ /**
+ * Install a packet filter.
+ * @param filter an APF program to filter incoming packets.
+ * @return {@code true} if filter successfully installed, {@code false} otherwise.
+ */
+ protected boolean installPacketFilter(byte[] filter) {
+ return false;
+ }
+
protected void log(String s) {
Log.d(LOG_TAG, "NetworkAgent: " + s);
}
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
index 5511a24..748699e 100644
--- a/core/java/android/net/NetworkMisc.java
+++ b/core/java/android/net/NetworkMisc.java
@@ -56,6 +56,22 @@
*/
public String subscriberId;
+ /**
+ * Version of APF instruction set supported for packet filtering. 0 indicates no support for
+ * packet filtering using APF programs.
+ */
+ public int apfVersionSupported;
+
+ /**
+ * Maximum size of APF program allowed.
+ */
+ public int maximumApfProgramSize;
+
+ /**
+ * Format of packets passed to APF filter. Should be one of ARPHRD_*
+ */
+ public int apfPacketFormat;
+
public NetworkMisc() {
}
@@ -65,6 +81,9 @@
explicitlySelected = nm.explicitlySelected;
acceptUnvalidated = nm.acceptUnvalidated;
subscriberId = nm.subscriberId;
+ apfVersionSupported = nm.apfVersionSupported;
+ maximumApfProgramSize = nm.maximumApfProgramSize;
+ apfPacketFormat = nm.apfPacketFormat;
}
}
@@ -79,6 +98,9 @@
out.writeInt(explicitlySelected ? 1 : 0);
out.writeInt(acceptUnvalidated ? 1 : 0);
out.writeString(subscriberId);
+ out.writeInt(apfVersionSupported);
+ out.writeInt(maximumApfProgramSize);
+ out.writeInt(apfPacketFormat);
}
public static final Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() {
@@ -89,6 +111,9 @@
networkMisc.explicitlySelected = in.readInt() != 0;
networkMisc.acceptUnvalidated = in.readInt() != 0;
networkMisc.subscriberId = in.readString();
+ networkMisc.apfVersionSupported = in.readInt();
+ networkMisc.maximumApfProgramSize = in.readInt();
+ networkMisc.apfPacketFormat = in.readInt();
return networkMisc;
}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 94de933..8738424 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -68,10 +68,12 @@
public static final int FIREWALL_CHAIN_NONE = 0;
public static final int FIREWALL_CHAIN_DOZABLE = 1;
public static final int FIREWALL_CHAIN_STANDBY = 2;
+ public static final int FIREWALL_CHAIN_POWERSAVE = 3;
public static final String FIREWALL_CHAIN_NAME_NONE = "none";
public static final String FIREWALL_CHAIN_NAME_DOZABLE = "dozable";
public static final String FIREWALL_CHAIN_NAME_STANDBY = "standby";
+ public static final String FIREWALL_CHAIN_NAME_POWERSAVE = "powersave";
private static final boolean ALLOW_PLATFORM_APP_POLICY = true;
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index c6d919f..555032d 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -62,6 +62,13 @@
public native static void attachDhcpFilter(FileDescriptor fd) throws SocketException;
/**
+ * Attaches a socket filter that accepts ICMP6 router advertisement packets to the given socket.
+ * @param fd the socket's {@link FileDescriptor}.
+ * @param packetType the hardware address type, one of ARPHRD_*.
+ */
+ public native static void attachRaFilter(FileDescriptor fd, int packetType) throws SocketException;
+
+ /**
* Binds the current process to the network designated by {@code netId}. All sockets created
* in the future (and not explicitly bound via a bound {@link SocketFactory} (see
* {@link Network#getSocketFactory}) will be bound to this network. Note that if this
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 9984755..8fd3b0c 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -383,6 +383,9 @@
public static final int SIGNAL_KILL = 9;
public static final int SIGNAL_USR1 = 10;
+ private static long sStartElapsedRealtime;
+ private static long sStartUptimeMillis;
+
/**
* State for communicating with the zygote process.
*
@@ -772,6 +775,26 @@
public static final native long getElapsedCpuTime();
/**
+ * Return the {@link SystemClock#elapsedRealtime()} at which this process was started.
+ */
+ public static final long getStartElapsedRealtime() {
+ return sStartElapsedRealtime;
+ }
+
+ /**
+ * Return the {@link SystemClock#uptimeMillis()} at which this process was started.
+ */
+ public static final long getStartUptimeMillis() {
+ return sStartUptimeMillis;
+ }
+
+ /** @hide */
+ public static final void setStartTimes(long elapsedRealtime, long uptimeMillis) {
+ sStartElapsedRealtime = elapsedRealtime;
+ sStartUptimeMillis = uptimeMillis;
+ }
+
+ /**
* Returns true if the current process is a 64-bit runtime.
*/
public static final boolean is64Bit() {
diff --git a/core/java/android/os/ServiceSpecificException.java b/core/java/android/os/ServiceSpecificException.java
index 20f237a5..04fca19 100644
--- a/core/java/android/os/ServiceSpecificException.java
+++ b/core/java/android/os/ServiceSpecificException.java
@@ -20,20 +20,23 @@
*
* <p>This exception includes an error code specific to the throwing
* service. This is mostly used by system services to indicate
- * domain specific error conditions.
+ * domain specific error conditions.</p>
+ *
+ * <p>Since these exceptions are designed to be passed through Binder
+ * interfaces, and to be generated by native-code Binder services,
+ * they do not support exception chaining.</p>
*
* @hide
*/
public class ServiceSpecificException extends RuntimeException {
public final int errorCode;
- ServiceSpecificException(int errorCode, String message) {
+ public ServiceSpecificException(int errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
- ServiceSpecificException(int errorCode) {
+ public ServiceSpecificException(int errorCode) {
this.errorCode = errorCode;
}
}
-
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 6e9e456..7223dfb 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1658,7 +1658,7 @@
* android.graphics.drawable.Drawable, UserHandle, android.graphics.Rect, int)}.
* <p>
* If the original drawable is a BitmapDrawable and the backing bitmap is
- * mutable as per {@link android.graphics.Bitmap#isMutable()}, the bading
+ * mutable as per {@link android.graphics.Bitmap#isMutable()}, the badging
* is performed in place and the original drawable is returned.
* </p>
*
@@ -1681,17 +1681,17 @@
* badge to be used.
* <p>
* If the original drawable is a BitmapDrawable and the backing bitmap is
- * mutable as per {@link android.graphics.Bitmap#isMutable()}, the bading
+ * mutable as per {@link android.graphics.Bitmap#isMutable()}, the badging
* is performed in place and the original drawable is returned.
* </p>
*
* @param badgedDrawable The drawable to badge.
* @param user The target user.
* @param badgeLocation Where in the bounds of the badged drawable to place
- * the badge. If not provided, the badge is applied on top of the entire
+ * the badge. If it's {@code null}, the badge is applied on top of the entire
* drawable being badged.
* @param badgeDensity The optional desired density for the badge as per
- * {@link android.util.DisplayMetrics#densityDpi}. If not provided,
+ * {@link android.util.DisplayMetrics#densityDpi}. If it's not positive,
* the density of the display is used.
* @return A drawable that combines the original drawable and a badge as
* determined by the system.
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 904b393..4b43f53 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -8763,6 +8763,15 @@
* <li><em>Note: Some apps may choose to use phone number as the unique contact ID in DATA1.
* If this applies to you and you’d like phone number to be shown below the Contact Name by
* the Voice Assistant, then you may choose to leave DATA3 empty.</em></li>
+ * <li><em>Note: If your app also uses DATA3 to display contact details in the Contacts App,
+ * make sure it does not include prefix text such as "Message +<phone>" or "Free Message
+ * +<phone>", etc. If you must show the prefix text in the Contacts App, please use a
+ * different DATA# column, and update your contacts.xml to point to this new column. </em>
+ * </li>
+ * <li>Everytime the user sends a message to a contact, your app may choose to update the
+ * {@link ContactOptionsColumns#TIMES_CONTACTED} entry through DataUsageFeedback class.
+ * Doing this will allow Voice Assistant to bias speech recognition to contacts frequently
+ * contacted, this is particularly useful for contact names that are hard to pronounce.</li>
* </ul>
* <p>
* Input: {@link android.content.Intent#getType} is the MIME type of the data being sent.
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 3788c74..0065cd9 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -478,7 +478,6 @@
/**
* Capacity of a root in bytes. This column is optional, and may be
* {@code null} if unknown or unbounded.
- * {@hide}
* <p>
* Type: INTEGER (long)
*/
@@ -568,6 +567,22 @@
* @hide
*/
public static final int FLAG_HAS_SETTINGS = 1 << 17;
+
+ /**
+ * Flag indicating that this root is on removable SD card storage.
+ *
+ * @see #COLUMN_FLAGS
+ * @hide
+ */
+ public static final int FLAG_REMOVABLE_SD = 1 << 18;
+
+ /**
+ * Flag indicating that this root is on removable USB storage.
+ *
+ * @see #COLUMN_FLAGS
+ * @hide
+ */
+ public static final int FLAG_REMOVABLE_USB = 1 << 19;
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cb45deb..a40cf96 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1241,6 +1241,19 @@
public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS
= "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
+ /**
+ * Activity Action: Show a dialog for remote bugreport flow.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SHOW_REMOTE_BUGREPORT_DIALOG
+ = "android.settings.SHOW_REMOTE_BUGREPORT_DIALOG";
+
// End of Intent actions for Settings
/**
@@ -4522,6 +4535,13 @@
public static final String USER_SETUP_COMPLETE = "user_setup_complete";
/**
+ * Prefix for category name that marks whether a suggested action from that category was
+ * completed.
+ * @hide
+ */
+ public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category.";
+
+ /**
* List of input methods that are currently enabled. This is a string
* containing the IDs of all enabled input methods, each ID separated
* by ':'.
diff --git a/core/java/android/service/carrier/CarrierMessagingService.java b/core/java/android/service/carrier/CarrierMessagingService.java
index f5396a3..140341c 100644
--- a/core/java/android/service/carrier/CarrierMessagingService.java
+++ b/core/java/android/service/carrier/CarrierMessagingService.java
@@ -51,6 +51,30 @@
= "android.service.carrier.CarrierMessagingService";
/**
+ * The default bitmask value passed to the callback of {@link #onReceiveTextSms} with all
+ * {@code RECEIVE_OPTIONS_x} flags cleared to indicate that the message should be kept and a
+ * new message notification should be shown.
+ *
+ * @see #RECEIVE_OPTIONS_DROP
+ * @see #RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE
+ */
+ public static final int RECEIVE_OPTIONS_DEFAULT = 0;
+
+ /**
+ * Used to set the flag in the bitmask passed to the callback of {@link #onReceiveTextSms} to
+ * indicate that the inbound SMS should be dropped.
+ */
+ public static final int RECEIVE_OPTIONS_DROP = 0x1;
+
+ /**
+ * Used to set the flag in the bitmask passed to the callback of {@link #onReceiveTextSms} to
+ * indicate that a new message notification should not be shown to the user when the
+ * credential-encrypted storage of the device is not available before the user unlocks the
+ * phone. It is only applicable to devices that support file-based encryption.
+ */
+ public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE = 0x2;
+
+ /**
* Indicates that an SMS or MMS message was successfully sent.
*/
public static final int SEND_STATUS_OK = 0;
@@ -96,7 +120,9 @@
* @param subId SMS subscription ID of the SIM
* @param callback result callback. Call with {@code true} to keep an inbound SMS message and
* deliver to SMS apps, and {@code false} to drop the message.
+ * @deprecated Use {@link #onReceiveTextSms} instead.
*/
+ @Deprecated
public void onFilterSms(@NonNull MessagePdu pdu, @NonNull String format, int destPort,
int subId, @NonNull ResultCallback<Boolean> callback) {
// optional
@@ -107,6 +133,36 @@
}
/**
+ * Override this method to filter inbound SMS messages.
+ *
+ * <p>This method will be called once for every incoming text SMS. You can invoke the callback
+ * with a bitmask to tell the platform how to handle the SMS. For a SMS received on a
+ * file-based encryption capable device while the credential-encrypted storage is not available,
+ * this method will be called for the second time when the credential-encrypted storage becomes
+ * available after the user unlocks the phone, if the bit {@link #RECEIVE_OPTIONS_DROP} is not
+ * set when invoking the callback.
+ *
+ * @param pdu the PDUs of the message
+ * @param format the format of the PDUs, typically "3gpp" or "3gpp2"
+ * @param destPort the destination port of a binary SMS, this will be -1 for text SMS
+ * @param subId SMS subscription ID of the SIM
+ * @param callback result callback. Call with a bitmask integer to indicate how the incoming
+ * text SMS should be handled by the platform. Use {@link #RECEIVE_OPTIONS_DROP} and
+ * {@link #RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE}
+ * to set the flags in the bitmask.
+ */
+ public void onReceiveTextSms(@NonNull MessagePdu pdu, @NonNull String format,
+ int destPort, int subId, @NonNull final ResultCallback<Integer> callback) {
+ onFilterSms(pdu, format, destPort, subId, new ResultCallback<Boolean>() {
+ @Override
+ public void onReceiveResult(Boolean result) throws RemoteException {
+ callback.onReceiveResult(result ? RECEIVE_OPTIONS_DEFAULT : RECEIVE_OPTIONS_DROP
+ | RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE);
+ }
+ });
+ }
+
+ /**
* Override this method to intercept text SMSs sent from the device.
* @deprecated Override {@link #onSendTextSms} below instead.
*
@@ -408,10 +464,11 @@
@Override
public void filterSms(MessagePdu pdu, String format, int destPort,
int subId, final ICarrierMessagingCallback callback) {
- onFilterSms(pdu, format, destPort, subId, new ResultCallback<Boolean>() {
+ onReceiveTextSms(pdu, format, destPort, subId,
+ new ResultCallback<Integer>() {
@Override
- public void onReceiveResult(final Boolean result) throws RemoteException {
- callback.onFilterComplete(result);
+ public void onReceiveResult(Integer options) throws RemoteException {
+ callback.onFilterComplete(options);
}
});
}
diff --git a/core/java/android/service/carrier/ICarrierMessagingCallback.aidl b/core/java/android/service/carrier/ICarrierMessagingCallback.aidl
index 6118a20..2753669 100644
--- a/core/java/android/service/carrier/ICarrierMessagingCallback.aidl
+++ b/core/java/android/service/carrier/ICarrierMessagingCallback.aidl
@@ -22,7 +22,7 @@
* @hide
*/
oneway interface ICarrierMessagingCallback {
- void onFilterComplete(boolean keepMessage);
+ void onFilterComplete(int result);
void onSendSmsComplete(int result, int messageRef);
void onSendMultipartSmsComplete(int result, in int[] messageRefs);
void onSendMmsComplete(int result, in byte[] sendConfPdu);
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index e79dfca..3564e11 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -16,6 +16,7 @@
package android.text.method;
+import android.graphics.Paint;
import android.icu.lang.UCharacter;
import android.icu.lang.UProperty;
import android.view.KeyEvent;
@@ -25,6 +26,8 @@
import android.text.style.ReplacementSpan;
import android.widget.TextView;
+import com.android.internal.annotations.GuardedBy;
+
import java.text.BreakIterator;
import java.util.Arrays;
import java.util.Collections;
@@ -45,6 +48,11 @@
implements KeyListener {
/* package */ static final Object OLD_SEL_START = new NoCopySpan.Concrete();
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ static Paint sCachedPaint = null;
+
/**
* Performs the action that happens when you press the {@link KeyEvent#KEYCODE_DEL} key in
* a {@link TextView}. If there is a selection, deletes the selection; otherwise,
@@ -258,20 +266,15 @@
}
// Returns the end offset to be deleted by a forward delete key from the given offset.
- private static int getOffsetForForwardDeleteKey(CharSequence text, int offset) {
+ private static int getOffsetForForwardDeleteKey(CharSequence text, int offset, Paint paint) {
final int len = text.length();
if (offset >= len - 1) {
return len;
}
- int codePoint = Character.codePointAt(text, offset);
- offset += Character.charCount(codePoint);
- if (offset == len) {
- return len;
- }
-
- // TODO: Handle emoji, combining chars, etc.
+ offset = paint.getTextRunCursor(text, offset, len, Paint.DIRECTION_LTR /* not used */,
+ offset, Paint.CURSOR_AFTER);
return adjustReplacementSpan(text, offset, false /* move to the end */);
}
@@ -311,7 +314,18 @@
final int start = Selection.getSelectionEnd(content);
final int end;
if (isForwardDelete) {
- end = getOffsetForForwardDeleteKey(content, start);
+ final Paint paint;
+ if (view instanceof TextView) {
+ paint = ((TextView)view).getPaint();
+ } else {
+ synchronized (mLock) {
+ if (sCachedPaint == null) {
+ sCachedPaint = new Paint();
+ }
+ paint = sCachedPaint;
+ }
+ }
+ end = getOffsetForForwardDeleteKey(content, start, paint);
} else {
end = getOffsetForBackspaceKey(content, start);
}
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index fbd9924..bd376ea 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -224,7 +224,7 @@
}
if ((mask & EMAIL_ADDRESSES) != 0) {
- gatherLinks(links, text, Patterns.EMAIL_ADDRESS,
+ gatherLinks(links, text, Patterns.AUTOLINK_EMAIL_ADDRESS,
new String[] { "mailto:" },
null, null);
}
diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java
index fc39004..fa3921c 100644
--- a/core/java/android/util/LocaleList.java
+++ b/core/java/android/util/LocaleList.java
@@ -478,8 +478,6 @@
/**
* Returns the default locale list, adjusted by moving the default locale to its first
* position.
- *
- * {@hide}
*/
@NonNull @Size(min=1)
public static LocaleList getAdjustedDefault() {
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index 9f2bcfd..9ed4850 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -394,6 +394,36 @@
public static final Pattern AUTOLINK_WEB_URL = Pattern.compile(
"(" + WEB_URL_WITH_PROTOCOL + "|" + WEB_URL_WITHOUT_PROTOCOL + ")");
+ /**
+ * Regular expression for valid email characters. Does not include some of the valid characters
+ * defined in RFC5321: #&~!^`{}/=$*?|
+ */
+ private static final String EMAIL_CHAR = LABEL_CHAR + "\\+\\-_%'";
+
+ /**
+ * Regular expression for local part of an email address. RFC5321 section 4.5.3.1.1 limits
+ * the local part to be at most 64 octets.
+ */
+ private static final String EMAIL_ADDRESS_LOCAL_PART =
+ "[" + EMAIL_CHAR + "]" + "(?:[" + EMAIL_CHAR + "\\.]{1,62}[" + EMAIL_CHAR + "])?";
+
+ /**
+ * Regular expression for the domain part of an email address. RFC5321 section 4.5.3.1.2 limits
+ * the domain to be at most 255 octets.
+ */
+ private static final String EMAIL_ADDRESS_DOMAIN =
+ "(?=.{1,255}(?:\\s|$|^))" + HOST_NAME;
+
+ /**
+ * Regular expression pattern to match email addresses. It excludes double quoted local parts
+ * and the special characters #&~!^`{}/=$*?| that are included in RFC5321.
+ * @hide
+ */
+ public static final Pattern AUTOLINK_EMAIL_ADDRESS = Pattern.compile("(" + WORD_BOUNDARY +
+ "(?:" + EMAIL_ADDRESS_LOCAL_PART + "@" + EMAIL_ADDRESS_DOMAIN + ")" +
+ WORD_BOUNDARY + ")"
+ );
+
public static final Pattern EMAIL_ADDRESS
= Pattern.compile(
"[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" +
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 728f723..60c7270 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -75,6 +75,36 @@
public static final int SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID = 2;
/**
+ * Returns {@code true} if the provided APK contains an APK Signature Scheme V2
+ * signature. The signature will not be verified.
+ */
+ public static boolean hasSignature(String apkFile) throws IOException {
+ try (RandomAccessFile apk = new RandomAccessFile(apkFile, "r")) {
+ long fileSize = apk.length();
+ if (fileSize > Integer.MAX_VALUE) {
+ return false;
+ }
+ MappedByteBuffer apkContents =
+ apk.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, fileSize);
+ // ZipUtils and APK Signature Scheme v2 verifier expect little-endian byte order.
+ apkContents.order(ByteOrder.LITTLE_ENDIAN);
+
+ final int centralDirOffset =
+ (int) getCentralDirOffset(apkContents, getEocdOffset(apkContents));
+ // Find the APK Signing Block.
+ int apkSigningBlockOffset = findApkSigningBlock(apkContents, centralDirOffset);
+ ByteBuffer apkSigningBlock =
+ sliceFromTo(apkContents, apkSigningBlockOffset, centralDirOffset);
+
+ // Find the APK Signature Scheme v2 Block inside the APK Signing Block.
+ findApkSignatureSchemeV2Block(apkSigningBlock);
+ return true;
+ } catch (SignatureNotFoundException e) {
+ }
+ return false;
+ }
+
+ /**
* Verifies APK Signature Scheme v2 signatures of the provided APK and returns the certificates
* associated with each signer.
*
@@ -130,31 +160,8 @@
// ZipUtils and APK Signature Scheme v2 verifier expect little-endian byte order.
apkContents.order(ByteOrder.LITTLE_ENDIAN);
- // Find the offset of ZIP End of Central Directory (EoCD)
- int eocdOffset = ZipUtils.findZipEndOfCentralDirectoryRecord(apkContents);
- if (eocdOffset == -1) {
- throw new SignatureNotFoundException(
- "Not an APK file: ZIP End of Central Directory record not found");
- }
- if (ZipUtils.isZip64EndOfCentralDirectoryLocatorPresent(apkContents, eocdOffset)) {
- throw new SignatureNotFoundException("ZIP64 APK not supported");
- }
- ByteBuffer eocd = sliceFromTo(apkContents, eocdOffset, apkContents.capacity());
-
- // Look up the offset of ZIP Central Directory.
- long centralDirOffsetLong = ZipUtils.getZipEocdCentralDirectoryOffset(eocd);
- if (centralDirOffsetLong >= eocdOffset) {
- throw new SignatureNotFoundException(
- "ZIP Central Directory offset out of range: " + centralDirOffsetLong
- + ". ZIP End of Central Directory offset: " + eocdOffset);
- }
- long centralDirSizeLong = ZipUtils.getZipEocdCentralDirectorySizeBytes(eocd);
- if (centralDirOffsetLong + centralDirSizeLong != eocdOffset) {
- throw new SignatureNotFoundException(
- "ZIP Central Directory is not immediately followed by End of Central"
- + " Directory");
- }
- int centralDirOffset = (int) centralDirOffsetLong;
+ final int eocdOffset = getEocdOffset(apkContents);
+ final int centralDirOffset = (int) getCentralDirOffset(apkContents, eocdOffset);
// Find the APK Signing Block.
int apkSigningBlockOffset = findApkSigningBlock(apkContents, centralDirOffset);
@@ -499,6 +506,43 @@
return result;
}
+ /**
+ * Finds the offset of ZIP End of Central Directory (EoCD).
+ *
+ * @throws SignatureNotFoundException If the EoCD could not be found
+ */
+ private static int getEocdOffset(ByteBuffer apkContents) throws SignatureNotFoundException {
+ int eocdOffset = ZipUtils.findZipEndOfCentralDirectoryRecord(apkContents);
+ if (eocdOffset == -1) {
+ throw new SignatureNotFoundException(
+ "Not an APK file: ZIP End of Central Directory record not found");
+ }
+ return eocdOffset;
+ }
+
+ private static long getCentralDirOffset(ByteBuffer apkContents, int eocdOffset)
+ throws SignatureNotFoundException {
+ if (ZipUtils.isZip64EndOfCentralDirectoryLocatorPresent(apkContents, eocdOffset)) {
+ throw new SignatureNotFoundException("ZIP64 APK not supported");
+ }
+ ByteBuffer eocd = sliceFromTo(apkContents, eocdOffset, apkContents.capacity());
+
+ // Look up the offset of ZIP Central Directory.
+ long centralDirOffsetLong = ZipUtils.getZipEocdCentralDirectoryOffset(eocd);
+ if (centralDirOffsetLong >= eocdOffset) {
+ throw new SignatureNotFoundException(
+ "ZIP Central Directory offset out of range: " + centralDirOffsetLong
+ + ". ZIP End of Central Directory offset: " + eocdOffset);
+ }
+ long centralDirSizeLong = ZipUtils.getZipEocdCentralDirectorySizeBytes(eocd);
+ if (centralDirOffsetLong + centralDirSizeLong != eocdOffset) {
+ throw new SignatureNotFoundException(
+ "ZIP Central Directory is not immediately followed by End of Central"
+ + " Directory");
+ }
+ return centralDirOffsetLong;
+ }
+
private static final int getChunkCount(int inputSizeBytes) {
return (inputSizeBytes + CHUNK_SIZE_BYTES - 1) / CHUNK_SIZE_BYTES;
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 9543acf..8048301 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -167,7 +167,7 @@
in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
void setAppVisibility(IBinder token, boolean visible);
- void notifyAppStopped(IBinder token);
+ void notifyAppStopped(IBinder token, boolean stopped);
void startAppFreezingScreen(IBinder token, int configChanges);
void stopAppFreezingScreen(IBinder token, boolean force);
void removeAppToken(IBinder token);
diff --git a/core/java/android/view/Surface.aidl b/core/java/android/view/Surface.aidl
deleted file mode 100644
index 90bf37a..0000000
--- a/core/java/android/view/Surface.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/* //device/java/android/android/view/Surface.aidl
-**
-** Copyright 2007, 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;
-
-parcelable Surface;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b58c68f..aa86c03 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -36,6 +36,7 @@
throws OutOfResourcesException;
private static native void nativeRelease(long nativeObject);
private static native void nativeDestroy(long nativeObject);
+ private static native void nativeDisconnect(long nativeObject);
private static native Bitmap nativeScreenshot(IBinder displayToken,
Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
@@ -341,6 +342,15 @@
mCloseGuard.close();
}
+ /**
+ * Disconnect any client still connected to the surface.
+ */
+ public void disconnect() {
+ if (mNativeObject != 0) {
+ nativeDisconnect(mNativeObject);
+ }
+ }
+
private void checkNotReleased() {
if (mNativeObject == 0) throw new NullPointerException(
"mNativeObject is null. Have you called release() already?");
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index 65c7654..42d1442 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -21,13 +21,22 @@
import android.view.KeyEvent;
/**
- * <p>Wrapper class for proxying calls to another InputConnection. Subclass
- * and have fun!
+ * <p>Wrapper class for proxying calls to another InputConnection. Subclass and have fun!
*/
public class InputConnectionWrapper implements InputConnection {
private InputConnection mTarget;
final boolean mMutable;
-
+
+ /**
+ * Initializes a wrapper.
+ *
+ * <p><b>Caveat:</b> Although the system can accept {@code (InputConnection) null} in some
+ * places, you cannot emulate such a behavior by non-null {@link InputConnectionWrapper} that
+ * has {@code null} in {@code target}.</p>
+ * @param target the {@link InputConnection} to be proxied.
+ * @param mutable set {@code true} to protect this object from being reconfigured to target
+ * another {@link InputConnection}. Note that this is ignored while the target is {@code null}.
+ */
public InputConnectionWrapper(InputConnection target, boolean mutable) {
mMutable = mutable;
mTarget = target;
@@ -35,6 +44,12 @@
/**
* Change the target of the input connection.
+ *
+ * <p><b>Caveat:</b> Although the system can accept {@code (InputConnection) null} in some
+ * places, you cannot emulate such a behavior by non-null {@link InputConnectionWrapper} that
+ * has {@code null} in {@code target}.</p>
+ * @param target the {@link InputConnection} to be proxied.
+ * @throws SecurityException when this wrapper has non-null target and is immutable.
*/
public void setTarget(InputConnection target) {
if (mTarget != null && !mMutable) {
@@ -42,99 +57,195 @@
}
mTarget = target;
}
-
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public CharSequence getTextBeforeCursor(int n, int flags) {
return mTarget.getTextBeforeCursor(n, flags);
}
-
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public CharSequence getTextAfterCursor(int n, int flags) {
return mTarget.getTextAfterCursor(n, flags);
}
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public CharSequence getSelectedText(int flags) {
return mTarget.getSelectedText(flags);
}
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public int getCursorCapsMode(int reqModes) {
return mTarget.getCursorCapsMode(reqModes);
}
-
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
return mTarget.getExtractedText(request, flags);
}
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
return mTarget.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
}
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
return mTarget.deleteSurroundingText(beforeLength, afterLength);
}
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean setComposingText(CharSequence text, int newCursorPosition) {
return mTarget.setComposingText(text, newCursorPosition);
}
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean setComposingRegion(int start, int end) {
return mTarget.setComposingRegion(start, end);
}
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean finishComposingText() {
return mTarget.finishComposingText();
}
-
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean commitText(CharSequence text, int newCursorPosition) {
return mTarget.commitText(text, newCursorPosition);
}
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean commitCompletion(CompletionInfo text) {
return mTarget.commitCompletion(text);
}
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean commitCorrection(CorrectionInfo correctionInfo) {
return mTarget.commitCorrection(correctionInfo);
}
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean setSelection(int start, int end) {
return mTarget.setSelection(start, end);
}
-
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean performEditorAction(int editorAction) {
return mTarget.performEditorAction(editorAction);
}
-
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean performContextMenuAction(int id) {
return mTarget.performContextMenuAction(id);
}
-
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean beginBatchEdit() {
return mTarget.beginBatchEdit();
}
-
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean endBatchEdit() {
return mTarget.endBatchEdit();
}
-
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean sendKeyEvent(KeyEvent event) {
return mTarget.sendKeyEvent(event);
}
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean clearMetaKeyStates(int states) {
return mTarget.clearMetaKeyStates(states);
}
-
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean reportFullscreenMode(boolean enabled) {
return mTarget.reportFullscreenMode(enabled);
}
-
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean performPrivateCommand(String action, Bundle data) {
return mTarget.performPrivateCommand(action, data);
}
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public boolean requestCursorUpdates(int cursorUpdateMode) {
return mTarget.requestCursorUpdates(cursorUpdateMode);
}
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
public Handler getHandler() {
return mTarget.getHandler();
}
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index 1d242d3..434e3eb 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -117,6 +117,16 @@
Selection.extendSelection(getText(), index);
}
+ /**
+ * Causes words in the text that are longer than the view's width to be ellipsized instead of
+ * broken in the middle. {@link TextUtils.TruncateAt#MARQUEE
+ * TextUtils.TruncateAt#MARQUEE} is not supported.
+ *
+ * @param ellipsis Type of ellipsis to be applied.
+ * @throws IllegalArgumentException When the value of <code>ellipsis</code> parameter is
+ * {@link TextUtils.TruncateAt#MARQUEE}.
+ * @see TextView#setEllipsize(TextUtils.TruncateAt)
+ */
@Override
public void setEllipsize(TextUtils.TruncateAt ellipsis) {
if (ellipsis == TextUtils.TruncateAt.MARQUEE) {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 881e5cd..a7b12c1 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -215,7 +215,7 @@
boolean mInBatchEditControllers;
boolean mShowSoftInputOnFocus = true;
- boolean mPreserveDetachedSelection;
+ private boolean mPreserveDetachedSelection;
boolean mTemporaryDetach;
boolean mIsBeingLongClicked;
@@ -352,7 +352,6 @@
void replace() {
int middle = (mTextView.getSelectionStart() + mTextView.getSelectionEnd()) / 2;
- stopTextActionMode();
Selection.setSelection((Spannable) mTextView.getText(), middle);
showSuggestions();
}
@@ -429,10 +428,8 @@
mSpellChecker = null;
}
- mPreserveDetachedSelection = true;
hideCursorAndSpanControllers();
- stopTextActionMode();
- mPreserveDetachedSelection = false;
+ stopTextActionModeWithPreservingSelection();
mTemporaryDetach = false;
}
@@ -1104,7 +1101,6 @@
mInsertionControllerEnabled) {
final int offset = mTextView.getOffsetForPosition(mLastDownPositionX,
mLastDownPositionY);
- stopTextActionMode();
Selection.setSelection((Spannable) mTextView.getText(), offset);
getInsertionController().show();
mIsInsertionActionModeStartPending = true;
@@ -1208,18 +1204,15 @@
mTextView.onEndBatchEdit();
if (mTextView.isInExtractedMode()) {
- // terminateTextSelectionMode removes selection, which we want to keep when
- // ExtractEditText goes out of focus.
- final int selStart = mTextView.getSelectionStart();
- final int selEnd = mTextView.getSelectionEnd();
hideCursorAndSpanControllers();
- stopTextActionMode();
- Selection.setSelection((Spannable) mTextView.getText(), selStart, selEnd);
+ stopTextActionModeWithPreservingSelection();
} else {
- if (mTemporaryDetach) mPreserveDetachedSelection = true;
hideCursorAndSpanControllers();
- stopTextActionMode();
- if (mTemporaryDetach) mPreserveDetachedSelection = false;
+ if (mTemporaryDetach) {
+ stopTextActionModeWithPreservingSelection();
+ } else {
+ stopTextActionMode();
+ }
downgradeEasyCorrectionSpans();
}
// No need to create the controller
@@ -1290,10 +1283,8 @@
makeBlink();
}
final InputMethodManager imm = InputMethodManager.peekInstance();
- final boolean immFullScreen = (imm != null && imm.isFullscreenMode());
- if (mSelectionModifierCursorController != null && mTextView.hasSelection()
- && !immFullScreen && mTextActionMode != null) {
- mSelectionModifierCursorController.show();
+ if (mTextView.hasSelection() && !extractedTextModeWillBeStarted()) {
+ startSelectionActionMode();
}
} else {
if (mBlink != null) {
@@ -1304,9 +1295,7 @@
}
// Order matters! Must be done before onParentLostFocus to rely on isShowingUp
hideCursorAndSpanControllers();
- if (mSelectionModifierCursorController != null) {
- mSelectionModifierCursorController.hide();
- }
+ stopTextActionModeWithPreservingSelection();
if (mSuggestionsPopupWindow != null) {
mSuggestionsPopupWindow.onParentLostFocus();
}
@@ -1856,6 +1845,38 @@
}
}
+ void refreshTextActionMode() {
+ if (extractedTextModeWillBeStarted()) {
+ return;
+ }
+ final boolean hasSelection = mTextView.hasSelection();
+ final SelectionModifierCursorController selectionController = getSelectionController();
+ final InsertionPointCursorController insertionController = getInsertionController();
+ if ((selectionController != null && selectionController.isCursorBeingModified())
+ || (insertionController != null && insertionController.isCursorBeingModified())) {
+ // ActionMode should be managed by the currently active cursor controller.
+ return;
+ }
+ if (hasSelection) {
+ if (mTextActionMode == null || selectionController == null
+ || !selectionController.isActive()) {
+ // Avoid dismissing the selection if it exists.
+ stopTextActionModeWithPreservingSelection();
+ startSelectionActionMode();
+ } else {
+ mTextActionMode.invalidateContentRect();
+ }
+ } else {
+ // Insertion action mode is started only when insertion controller is explicitly
+ // activated.
+ if (insertionController == null || !insertionController.isActive()) {
+ stopTextActionMode();
+ } else if (mTextActionMode != null) {
+ mTextActionMode.invalidateContentRect();
+ }
+ }
+ }
+
/**
* Start an Insertion action mode.
*/
@@ -1879,17 +1900,15 @@
/**
* Starts a Selection Action Mode with the current selection and ensures the selection handles
- * are shown if there is a selection, otherwise the insertion handle is shown. This should be
- * used when the mode is started from a non-touch event.
+ * are shown if there is a selection. This should be used when the mode is started from a
+ * non-touch event.
*
* @return true if the selection mode was actually started.
*/
- boolean startSelectionActionMode() {
+ private boolean startSelectionActionMode() {
boolean selectionStarted = startSelectionActionModeInternal();
if (selectionStarted) {
getSelectionController().show();
- } else if (getInsertionController() != null) {
- getInsertionController().show();
}
return selectionStarted;
}
@@ -1907,66 +1926,52 @@
if (extractedTextModeWillBeStarted()) {
return false;
}
- if (mTextActionMode != null) {
- mTextActionMode.finish();
- }
- if (!checkFieldAndSelectCurrentWord()) {
+ if (!checkField()) {
return false;
}
-
- // Avoid dismissing the selection if it exists.
- mPreserveDetachedSelection = true;
- stopTextActionMode();
- mPreserveDetachedSelection = false;
-
+ if (!mTextView.hasSelection() && !selectCurrentWord()) {
+ // No selection and cannot select a word.
+ return false;
+ }
+ stopTextActionModeWithPreservingSelection();
getSelectionController().enterDrag(
SelectionModifierCursorController.DRAG_ACCELERATOR_MODE_WORD);
return true;
}
/**
- * Checks whether a selection can be performed on the current TextView and if so selects
- * the current word.
+ * Checks whether a selection can be performed on the current TextView.
*
- * @return true if there already was a selection or if the current word was selected.
+ * @return true if a selection can be performed
*/
- boolean checkFieldAndSelectCurrentWord() {
+ boolean checkField() {
if (!mTextView.canSelectText() || !mTextView.requestFocus()) {
Log.w(TextView.LOG_TAG,
"TextView does not support text selection. Selection cancelled.");
return false;
}
-
- if (!mTextView.hasSelection()) {
- // There may already be a selection on device rotation
- return selectCurrentWord();
- }
return true;
}
private boolean startSelectionActionModeInternal() {
+ if (extractedTextModeWillBeStarted()) {
+ return false;
+ }
if (mTextActionMode != null) {
// Text action mode is already started
mTextActionMode.invalidate();
return false;
}
- if (!checkFieldAndSelectCurrentWord()) {
+ if (!checkField() || !mTextView.hasSelection()) {
return false;
}
- boolean willExtract = extractedTextModeWillBeStarted();
+ ActionMode.Callback actionModeCallback =
+ new TextActionModeCallback(true /* hasSelection */);
+ mTextActionMode = mTextView.startActionMode(actionModeCallback, ActionMode.TYPE_FLOATING);
- // Do not start the action mode when extracted text will show up full screen, which would
- // immediately hide the newly created action bar and would be visually distracting.
- if (!willExtract) {
- ActionMode.Callback actionModeCallback =
- new TextActionModeCallback(true /* hasSelection */);
- mTextActionMode = mTextView.startActionMode(
- actionModeCallback, ActionMode.TYPE_FLOATING);
- }
-
- final boolean selectionStarted = mTextActionMode != null || willExtract;
+ final boolean selectionStarted = mTextActionMode != null;
if (selectionStarted && !mTextView.isTextSelectable() && mShowSoftInputOnFocus) {
// Show the IME to be able to replace text, except when selecting non editable text.
final InputMethodManager imm = InputMethodManager.peekInstance();
@@ -2107,6 +2112,12 @@
}
}
+ private void stopTextActionModeWithPreservingSelection() {
+ mPreserveDetachedSelection = true;
+ stopTextActionMode();
+ mPreserveDetachedSelection = false;
+ }
+
/**
* @return True if this view supports insertion handles.
*/
@@ -2436,16 +2447,14 @@
if (offset == -1) {
return;
}
- mPreserveDetachedSelection = true;
- stopTextActionMode();
- mPreserveDetachedSelection = false;
+ stopTextActionModeWithPreservingSelection();
final boolean isOnSelection = mTextView.hasSelection()
&& offset >= mTextView.getSelectionStart() && offset <= mTextView.getSelectionEnd();
if (!isOnSelection) {
// Right clicked position is not on the selection. Remove the selection and move the
// cursor to the right clicked position.
- stopTextActionMode();
Selection.setSelection((Spannable) mTextView.getText(), offset);
+ stopTextActionMode();
}
if (shouldOfferToShowSuggestions()) {
@@ -3160,6 +3169,7 @@
mTextView.getContext(), mTextView.mTextEditSuggestionHighlightStyle);
private TextView mAddToDictionaryButton;
private TextView mDeleteButton;
+ private ListView mSuggestionListView;
private SuggestionSpan mMisspelledSpan;
private int mContainerMarginWidth;
private int mContainerMarginTop;
@@ -3177,7 +3187,7 @@
((Spannable) mTextView.getText()).removeSpan(mSuggestionRangeSpan);
mTextView.setCursorVisible(mCursorWasVisibleBeforeSuggestions);
- if (hasInsertionController()) {
+ if (hasInsertionController() && !extractedTextModeWillBeStarted()) {
getInsertionController().show();
}
}
@@ -3213,12 +3223,12 @@
mClippingLimitLeft = lp.leftMargin;
mClippingLimitRight = lp.rightMargin;
- final ListView suggestionListView = (ListView) relativeLayout.findViewById(
+ mSuggestionListView = (ListView) relativeLayout.findViewById(
com.android.internal.R.id.suggestionContainer);
mSuggestionsAdapter = new SuggestionAdapter();
- suggestionListView.setAdapter(mSuggestionsAdapter);
- suggestionListView.setOnItemClickListener(this);
+ mSuggestionListView.setAdapter(mSuggestionsAdapter);
+ mSuggestionListView.setOnItemClickListener(this);
// Inflate the suggestion items once and for all.
mSuggestionInfos = new SuggestionInfo[MAX_NUMBER_SUGGESTIONS];
@@ -3327,6 +3337,9 @@
@Override
public void show() {
if (!(mTextView.getText() instanceof Editable)) return;
+ if (extractedTextModeWillBeStarted()) {
+ return;
+ }
if (updateSuggestions()) {
mCursorWasVisibleBeforeSuggestions = mCursorVisible;
@@ -3374,6 +3387,7 @@
popupBackground.getPadding(mTempRect);
width += mTempRect.left + mTempRect.right;
}
+ mSuggestionListView.getLayoutParams().width = width;
mPopupWindow.setWidth(width);
}
@@ -3483,7 +3497,6 @@
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Editable editable = (Editable) mTextView.getText();
SuggestionInfo suggestionInfo = mSuggestionInfos[position];
-
final int spanStart = editable.getSpanStart(suggestionInfo.mSuggestionSpan);
final int spanEnd = editable.getSpanEnd(suggestionInfo.mSuggestionSpan);
if (spanStart < 0 || spanEnd <= spanStart) {
@@ -4386,7 +4399,7 @@
if (distanceSquared < touchSlop * touchSlop) {
// Tapping on the handle toggles the insertion action mode.
if (mTextActionMode != null) {
- mTextActionMode.finish();
+ stopTextActionMode();
} else {
startInsertionActionMode();
}
@@ -4803,6 +4816,10 @@
* preventing the activity from being recycled.
*/
public void onDetached();
+
+ public boolean isCursorBeingModified();
+
+ public boolean isActive();
}
private class InsertionPointCursorController implements CursorController {
@@ -4846,6 +4863,16 @@
if (mHandle != null) mHandle.onDetached();
}
+
+ @Override
+ public boolean isCursorBeingModified() {
+ return mHandle != null && mHandle.isDragging();
+ }
+
+ @Override
+ public boolean isActive() {
+ return mHandle != null && mHandle.isShowing();
+ }
}
class SelectionModifierCursorController implements CursorController {
@@ -5035,9 +5062,7 @@
if (mStartOffset != offset) {
// Start character based drag accelerator.
- if (mTextActionMode != null) {
- mTextActionMode.finish();
- }
+ stopTextActionMode();
enterDrag(DRAG_ACCELERATOR_MODE_CHARACTER);
mDiscardNextActionUp = true;
mHaventMovedEnoughToStartDrag = false;
@@ -5111,9 +5136,7 @@
if (mInsertionActionModeRunnable != null) {
mTextView.removeCallbacks(mInsertionActionModeRunnable);
}
- if (mTextActionMode != null) {
- mTextActionMode.finish();
- }
+ stopTextActionMode();
if (!selectCurrentParagraph()) {
return false;
}
@@ -5222,6 +5245,12 @@
mStartOffset = -1;
mDragAcceleratorMode = DRAG_ACCELERATOR_MODE_INACTIVE;
mSwitchedLines = false;
+ final int selectionStart = mTextView.getSelectionStart();
+ final int selectionEnd = mTextView.getSelectionEnd();
+ if (selectionStart > selectionEnd) {
+ Selection.setSelection((Spannable) mTextView.getText(),
+ selectionEnd, selectionStart);
+ }
}
/**
@@ -5231,6 +5260,12 @@
return mStartHandle != null && mStartHandle.isDragging();
}
+ @Override
+ public boolean isCursorBeingModified() {
+ return isDragAcceleratorActive() || isSelectionStartDragged()
+ || (mEndHandle != null && mEndHandle.isDragging());
+ }
+
/**
* @return true if the user is selecting text using the drag accelerator.
*/
@@ -5252,6 +5287,11 @@
if (mStartHandle != null) mStartHandle.onDetached();
if (mEndHandle != null) mEndHandle.onDetached();
}
+
+ @Override
+ public boolean isActive() {
+ return mStartHandle != null && mStartHandle.isShowing();
+ }
}
private class CorrectionHighlighter {
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 2099b04..72a50ec 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -17,21 +17,15 @@
package android.widget;
import android.animation.ObjectAnimator;
+import android.annotation.InterpolatorRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.graphics.PorterDuff;
-
-import android.util.FloatProperty;
-import android.util.IntProperty;
-import android.view.accessibility.AccessibilityNodeInfo;
-import com.android.internal.R;
-
-import android.annotation.InterpolatorRes;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.Animatable;
@@ -46,6 +40,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
+import android.util.FloatProperty;
import android.util.MathUtils;
import android.util.Pools.SynchronizedPool;
import android.view.Gravity;
@@ -55,6 +50,7 @@
import android.view.ViewHierarchyEncoder;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
@@ -63,6 +59,7 @@
import android.view.animation.LinearInterpolator;
import android.view.animation.Transformation;
import android.widget.RemoteViews.RemoteView;
+import com.android.internal.R;
import java.util.ArrayList;
@@ -606,15 +603,30 @@
if (indeterminate) {
// swap between indeterminate and regular backgrounds
- mCurrentDrawable = mIndeterminateDrawable;
+ swapCurrentDrawable(mIndeterminateDrawable);
startAnimation();
} else {
- mCurrentDrawable = mProgressDrawable;
+ swapCurrentDrawable(mProgressDrawable);
stopAnimation();
}
}
}
+ private void swapCurrentDrawable(Drawable newDrawable) {
+ final Drawable oldDrawable = mCurrentDrawable;
+ mCurrentDrawable = newDrawable;
+ if (oldDrawable != mCurrentDrawable) {
+ if (oldDrawable != null) {
+ oldDrawable.setVisible(false, false);
+ }
+ if (mCurrentDrawable != null) {
+ mCurrentDrawable.setVisible(
+ getVisibility() == VISIBLE && getWindowVisibility() == VISIBLE,
+ false);
+ }
+ }
+ }
+
/**
* <p>Get the drawable used to draw the progress bar in
* indeterminate mode.</p>
@@ -654,7 +666,7 @@
}
if (mIndeterminate) {
- mCurrentDrawable = d;
+ swapCurrentDrawable(d);
postInvalidate();
}
}
@@ -820,7 +832,7 @@
}
if (!mIndeterminate) {
- mCurrentDrawable = d;
+ swapCurrentDrawable(d);
postInvalidate();
}
@@ -1555,7 +1567,7 @@
* <p>Start the indeterminate progress animation.</p>
*/
void startAnimation() {
- if (getVisibility() != VISIBLE) {
+ if (getVisibility() != VISIBLE || getWindowVisibility() != VISIBLE) {
return;
}
@@ -1653,14 +1665,30 @@
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
+ updateVisibility();
+ }
+
+ @Override
+ protected void onWindowVisibilityChanged(@Visibility int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+
+ updateVisibility();
+ }
+
+ private void updateVisibility() {
+ final boolean isVisible = getVisibility() == VISIBLE && getWindowVisibility() == VISIBLE;
if (mIndeterminate) {
// let's be nice with the UI thread
- if (visibility == GONE || visibility == INVISIBLE) {
- stopAnimation();
- } else {
+ if (isVisible) {
startAnimation();
+ } else {
+ stopAnimation();
}
}
+
+ if (mCurrentDrawable != null) {
+ mCurrentDrawable.setVisible(isVisible, false);
+ }
}
@Override
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index f19bf02..73f8fdc 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -20,6 +20,7 @@
import android.R;
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
+import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
@@ -1510,6 +1511,9 @@
if (result != null) {
if (isTextEditable()) {
replaceSelectionWithText(result);
+ if (mEditor != null) {
+ mEditor.refreshTextActionMode();
+ }
} else {
if (result.length() > 0) {
Toast.makeText(getContext(), String.valueOf(result), Toast.LENGTH_LONG)
@@ -1519,12 +1523,7 @@
}
} else if (mText instanceof Spannable) {
// Reset the selection.
- stopTextActionMode();
- Selection.setSelection((Spannable) mText, getSelectionStart(), getSelectionEnd());
- }
-
- if (mEditor.hasSelectionController()) {
- mEditor.startSelectionActionMode();
+ Selection.setSelection((Spannable) mText, getSelectionEnd());
}
}
}
@@ -5392,11 +5391,7 @@
// - onFocusChanged cannot start it when focus is given to a view with selected text (after
// a screen rotation) since layout is not yet initialized at that point.
if (mEditor != null && mEditor.mCreatedWithASelection) {
- if (mEditor.extractedTextModeWillBeStarted()) {
- mEditor.checkFieldAndSelectCurrentWord();
- } else {
- mEditor.startSelectionActionMode();
- }
+ mEditor.refreshTextActionMode();
mEditor.mCreatedWithASelection = false;
}
@@ -5835,8 +5830,7 @@
final int layoutDirection = getLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
- if (mEllipsize == TextUtils.TruncateAt.MARQUEE &&
- mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
+ if (isMarqueeFadeEnabled()) {
if (!mSingleLine && getLineCount() == 1 && canMarquee() &&
(absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) {
final int width = mRight - mLeft;
@@ -6594,6 +6588,9 @@
// in the extracted view.
mEditor.hideCursorAndSpanControllers();
stopTextActionMode();
+ if (mEditor.mSelectionModifierCursorController != null) {
+ mEditor.mSelectionModifierCursorController.resetTouchOffsets();
+ }
}
/**
@@ -7888,7 +7885,7 @@
}
/**
- * Causes words in the text that are longer than the view is wide
+ * Causes words in the text that are longer than the view's width
* to be ellipsized instead of broken in the middle. You may also
* want to {@link #setSingleLine} or {@link #setHorizontallyScrolling}
* to constrain the text to a single line. Use <code>null</code>
@@ -8289,6 +8286,9 @@
if (newSelEnd < 0) {
newSelEnd = Selection.getSelectionEnd(buf);
}
+ if (mEditor != null) {
+ mEditor.refreshTextActionMode();
+ }
onSelectionChanged(newSelStart, newSelEnd);
}
}
@@ -8616,78 +8616,59 @@
@Override
protected float getLeftFadingEdgeStrength() {
- if (mEllipsize == TextUtils.TruncateAt.MARQUEE &&
- mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
- if (mMarquee != null && !mMarquee.isStopped()) {
- final Marquee marquee = mMarquee;
- if (marquee.shouldDrawLeftFade()) {
- final float scroll = marquee.getScroll();
- return scroll / getHorizontalFadingEdgeLength();
- } else {
- return 0.0f;
- }
- } else if (getLineCount() == 1) {
- final int layoutDirection = getLayoutDirection();
- final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
- switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.LEFT:
- return 0.0f;
- case Gravity.RIGHT:
- return (mLayout.getLineRight(0) - (mRight - mLeft) -
- getCompoundPaddingLeft() - getCompoundPaddingRight() -
- mLayout.getLineLeft(0)) / getHorizontalFadingEdgeLength();
- case Gravity.CENTER_HORIZONTAL:
- case Gravity.FILL_HORIZONTAL:
- final int textDirection = mLayout.getParagraphDirection(0);
- if (textDirection == Layout.DIR_LEFT_TO_RIGHT) {
- return 0.0f;
- } else {
- return (mLayout.getLineRight(0) - (mRight - mLeft) -
- getCompoundPaddingLeft() - getCompoundPaddingRight() -
- mLayout.getLineLeft(0)) / getHorizontalFadingEdgeLength();
- }
- }
+ if (isMarqueeFadeEnabled() && mMarquee != null && !mMarquee.isStopped()) {
+ final Marquee marquee = mMarquee;
+ if (marquee.shouldDrawLeftFade()) {
+ return getHorizontalFadingEdgeStrength(marquee.getScroll(), 0.0f);
+ } else {
+ return 0.0f;
}
+ } else if (getLineCount() == 1) {
+ final float lineLeft = getLayout().getLineLeft(0);
+ if(lineLeft > mScrollX) return 0.0f;
+ return getHorizontalFadingEdgeStrength(mScrollX, lineLeft);
}
return super.getLeftFadingEdgeStrength();
}
@Override
protected float getRightFadingEdgeStrength() {
- if (mEllipsize == TextUtils.TruncateAt.MARQUEE &&
- mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
- if (mMarquee != null && !mMarquee.isStopped()) {
- final Marquee marquee = mMarquee;
- final float maxFadeScroll = marquee.getMaxFadeScroll();
- final float scroll = marquee.getScroll();
- return (maxFadeScroll - scroll) / getHorizontalFadingEdgeLength();
- } else if (getLineCount() == 1) {
- final int layoutDirection = getLayoutDirection();
- final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
- switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.LEFT:
- final int textWidth = (mRight - mLeft) - getCompoundPaddingLeft() -
- getCompoundPaddingRight();
- final float lineWidth = mLayout.getLineWidth(0);
- return (lineWidth - textWidth) / getHorizontalFadingEdgeLength();
- case Gravity.RIGHT:
- return 0.0f;
- case Gravity.CENTER_HORIZONTAL:
- case Gravity.FILL_HORIZONTAL:
- final int textDirection = mLayout.getParagraphDirection(0);
- if (textDirection == Layout.DIR_RIGHT_TO_LEFT) {
- return 0.0f;
- } else {
- return (mLayout.getLineWidth(0) - ((mRight - mLeft) -
- getCompoundPaddingLeft() - getCompoundPaddingRight())) /
- getHorizontalFadingEdgeLength();
- }
- }
- }
+ if (isMarqueeFadeEnabled() && mMarquee != null && !mMarquee.isStopped()) {
+ final Marquee marquee = mMarquee;
+ return getHorizontalFadingEdgeStrength(marquee.getMaxFadeScroll(), marquee.getScroll());
+ } else if (getLineCount() == 1) {
+ final float rightEdge = mScrollX + (getWidth() - getCompoundPaddingLeft() -
+ getCompoundPaddingRight());
+ final float lineRight = getLayout().getLineRight(0);
+ if(lineRight < rightEdge) return 0.0f;
+ return getHorizontalFadingEdgeStrength(rightEdge, lineRight);
}
return super.getRightFadingEdgeStrength();
}
+ /**
+ * Calculates the fading edge strength as the ratio of the distance between two
+ * horizontal positions to {@link View#getHorizontalFadingEdgeLength()}. Uses the absolute
+ * value for the distance calculation.
+ *
+ * @param position1 A horizontal position.
+ * @param position2 A horizontal position.
+ * @return Fading edge strength between [0.0f, 1.0f].
+ */
+ @FloatRange(from=0.0, to=1.0)
+ private final float getHorizontalFadingEdgeStrength(float position1, float position2) {
+ final int horizontalFadingEdgeLength = getHorizontalFadingEdgeLength();
+ if(horizontalFadingEdgeLength == 0) return 0.0f;
+ final float diff = Math.abs(position1 - position2);
+ if(diff > horizontalFadingEdgeLength) return 1.0f;
+ return diff / horizontalFadingEdgeLength;
+ }
+
+ private final boolean isMarqueeFadeEnabled() {
+ return mEllipsize == TextUtils.TruncateAt.MARQUEE &&
+ mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS;
+ }
+
@Override
protected int computeHorizontalScrollRange() {
if (mLayout != null) {
@@ -9218,10 +9199,6 @@
}
if (start >= 0 && start <= end && end <= text.length()) {
Selection.setSelection((Spannable) text, start, end);
- // Make sure selection mode is engaged.
- if (mEditor != null) {
- mEditor.startSelectionActionMode();
- }
return true;
}
}
@@ -9412,16 +9389,7 @@
switch (id) {
case ID_SELECT_ALL:
- // This starts an action mode if triggered from another action mode. Text is
- // highlighted, so that it can be bulk edited, like selectAllOnFocus does. Returns
- // true even if text is empty.
- boolean shouldRestartActionMode =
- mEditor != null && mEditor.mTextActionMode != null;
- stopTextActionMode();
selectAllText();
- if (shouldRestartActionMode) {
- mEditor.startSelectionActionMode();
- }
return true;
case ID_UNDO:
@@ -9447,7 +9415,6 @@
case ID_CUT:
setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max)));
deleteText_internal(min, max);
- stopTextActionMode();
return true;
case ID_COPY:
@@ -9703,12 +9670,6 @@
}
boolean selectAllText() {
- // Need to hide insert point cursor controller before settings selection, otherwise insert
- // point cursor controller obtains cursor update event and update cursor with cancelling
- // selection.
- if (mEditor != null) {
- mEditor.hideInsertionPointCursorController();
- }
final int length = mText.length();
Selection.setSelection((Spannable) mText, 0, length);
return length > 0;
@@ -9747,7 +9708,6 @@
}
}
}
- stopTextActionMode();
sLastCutCopyOrTextChangedTime = 0;
}
}
@@ -9760,7 +9720,7 @@
sharingIntent.removeExtra(android.content.Intent.EXTRA_TEXT);
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, selectedText);
getContext().startActivity(Intent.createChooser(sharingIntent, null));
- stopTextActionMode();
+ Selection.setSelection((Spannable) mText, getSelectionEnd());
}
}
@@ -10078,6 +10038,12 @@
&& getAccessibilitySelectionEnd() == end) {
return;
}
+ CharSequence text = getIterableTextForAccessibility();
+ if (Math.min(start, end) >= 0 && Math.max(start, end) <= text.length()) {
+ Selection.setSelection((Spannable) text, start, end);
+ } else {
+ Selection.removeSelection((Spannable) text);
+ }
// Hide all selection controllers used for adjusting selection
// since we are doing so explicitlty by other means and these
// controllers interact with how selection behaves.
@@ -10085,12 +10051,6 @@
mEditor.hideCursorAndSpanControllers();
mEditor.stopTextActionMode();
}
- CharSequence text = getIterableTextForAccessibility();
- if (Math.min(start, end) >= 0 && Math.max(start, end) <= text.length()) {
- Selection.setSelection((Spannable) text, start, end);
- } else {
- Selection.removeSelection((Spannable) text);
- }
}
/** @hide */
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
index aca93ab..d8d6e56 100644
--- a/core/java/com/android/internal/app/LocaleHelper.java
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -180,14 +180,16 @@
*/
public static final class LocaleInfoComparator implements Comparator<LocaleStore.LocaleInfo> {
private final Collator mCollator;
+ private final boolean mCountryMode;
/**
* Constructor.
*
* @param sortLocale the locale to be used for sorting.
*/
- public LocaleInfoComparator(Locale sortLocale) {
+ public LocaleInfoComparator(Locale sortLocale, boolean countryMode) {
mCollator = Collator.getInstance(sortLocale);
+ mCountryMode = countryMode;
}
/**
@@ -202,9 +204,9 @@
public int compare(LocaleStore.LocaleInfo lhs, LocaleStore.LocaleInfo rhs) {
// We don't care about the various suggestion types, just "suggested" (!= 0)
// and "all others" (== 0)
- if (lhs.isSuggested() == rhs.isSuggested()) {
+ if (mCountryMode || (lhs.isSuggested() == rhs.isSuggested())) {
// They are in the same "bucket" (suggested / others), so we compare the text
- return mCollator.compare(lhs.getLabel(), rhs.getLabel());
+ return mCollator.compare(lhs.getLabel(mCountryMode), rhs.getLabel(mCountryMode));
} else {
// One locale is suggested and one is not, so we put them in different "buckets"
return lhs.isSuggested() ? -1 : 1;
diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java
index 956ee8c..2ea225f 100644
--- a/core/java/com/android/internal/app/LocalePickerWithRegion.java
+++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java
@@ -50,7 +50,6 @@
private Set<LocaleStore.LocaleInfo> mLocaleList;
private LocaleStore.LocaleInfo mParentLocale;
private boolean mTranslatedOnly = false;
- private boolean mCountryMode = false;
/**
* Other classes can register to be notified when a locale was selected.
@@ -70,15 +69,14 @@
boolean translatedOnly) {
LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
boolean shouldShowTheList = localePicker.setListener(context, listener, parent,
- true /* country mode */, translatedOnly);
+ translatedOnly);
return shouldShowTheList ? localePicker : null;
}
public static LocalePickerWithRegion createLanguagePicker(Context context,
LocaleSelectedListener listener, boolean translatedOnly) {
LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
- localePicker.setListener(context, listener, null,
- false /* language mode */, translatedOnly);
+ localePicker.setListener(context, listener, /* parent */ null, translatedOnly);
return localePicker;
}
@@ -96,14 +94,7 @@
* "pretending" it was selected, and return false.</p>
*/
private boolean setListener(Context context, LocaleSelectedListener listener,
- LocaleStore.LocaleInfo parent, boolean countryMode, boolean translatedOnly) {
- if (countryMode && (parent == null || parent.getLocale() == null)) {
- // The list of countries is determined as all the countries where the parent language
- // is used.
- throw new IllegalArgumentException("The country selection list needs a parent.");
- }
-
- this.mCountryMode = countryMode;
+ LocaleStore.LocaleInfo parent, boolean translatedOnly) {
this.mParentLocale = parent;
this.mListener = listener;
this.mTranslatedOnly = translatedOnly;
@@ -116,7 +107,7 @@
Collections.addAll(langTagsToIgnore, langTags);
}
- if (countryMode) {
+ if (parent != null) {
mLocaleList = LocaleStore.getLevelLocales(context,
langTagsToIgnore, parent, translatedOnly);
if (mLocaleList.size() <= 1) {
@@ -138,13 +129,11 @@
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
- final Locale sortingLocale = (mCountryMode && mParentLocale != null)
- ? mParentLocale.getLocale()
- : Locale.getDefault();
-
- mAdapter = new SuggestedLocaleAdapter(mLocaleList, mCountryMode);
+ final boolean countryMode = mParentLocale != null;
+ final Locale sortingLocale = countryMode ? mParentLocale.getLocale() : Locale.getDefault();
+ mAdapter = new SuggestedLocaleAdapter(mLocaleList, countryMode);
final LocaleHelper.LocaleInfoComparator comp =
- new LocaleHelper.LocaleInfoComparator(sortingLocale);
+ new LocaleHelper.LocaleInfoComparator(sortingLocale, countryMode);
mAdapter.sort(comp);
setListAdapter(mAdapter);
}
@@ -164,12 +153,8 @@
public void onResume() {
super.onResume();
- if (mCountryMode) {
- if (mParentLocale == null) {
- this.getActivity().setTitle(R.string.country_selection_title);
- } else {
- this.getActivity().setTitle(mParentLocale.getFullNameNative());
- }
+ if (mParentLocale != null) {
+ this.getActivity().setTitle(mParentLocale.getFullNameNative());
} else {
this.getActivity().setTitle(R.string.language_selection_title);
}
@@ -182,7 +167,7 @@
final LocaleStore.LocaleInfo locale =
(LocaleStore.LocaleInfo) getListAdapter().getItem(position);
- if (mCountryMode || locale.getParent() != null) {
+ if (locale.getParent() != null) {
if (mListener != null) {
mListener.onLocaleSelected(locale);
}
@@ -205,7 +190,7 @@
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- if (!mCountryMode) {
+ if (mParentLocale == null) {
inflater.inflate(R.menu.language_selection_list, menu);
MenuItem mSearchMenuItem = menu.findItem(R.id.locale_search_menu);
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index 465c4d8..c4e6675 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -145,11 +145,11 @@
return mLangScriptKey;
}
- String getLabel() {
- if (getParent() == null || this.isSuggestionOfType(SUGGESTION_TYPE_SIM)) {
- return getFullNameNative();
- } else {
+ String getLabel(boolean countryMode) {
+ if (countryMode) {
return getFullCountryNameNative();
+ } else {
+ return getFullNameNative();
}
}
@@ -311,9 +311,7 @@
if (level == 2) {
if (parent != null) { // region selection
if (parentId.equals(li.getParent().toLanguageTag())) {
- if (!li.isSuggestionOfType(LocaleInfo.SUGGESTION_TYPE_SIM)) {
- result.add(li);
- }
+ result.add(li);
}
} else { // language selection
if (li.isSuggestionOfType(LocaleInfo.SUGGESTION_TYPE_SIM)) {
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
index 0d4a5aa..98102ea 100644
--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -156,7 +156,7 @@
TextView text = (TextView) convertView.findViewById(R.id.locale);
LocaleStore.LocaleInfo item = (LocaleStore.LocaleInfo) getItem(position);
- text.setText(item.getLabel());
+ text.setText(item.getLabel(mCountryMode));
text.setTextLocale(item.getLocale());
if (mCountryMode) {
int layoutDir = TextUtils.getLayoutDirectionFromLocale(item.getParent());
@@ -171,6 +171,9 @@
}
private boolean showHeaders() {
+ if (mCountryMode) { // never show suggestions in country mode
+ return false;
+ }
return mSuggestionCount != 0 && mSuggestionCount != mLocaleOptions.size();
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 4e48e45..f04bcf2 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -547,23 +547,25 @@
LocaleUtils.filterByLanguage(keyboardSubtypes, sSubtypeToLocale, systemLocales,
applicableSubtypes);
- boolean hasAsciiCapableKeyboard = false;
- final int numApplicationSubtypes = applicableSubtypes.size();
- for (int i = 0; i < numApplicationSubtypes; ++i) {
- final InputMethodSubtype subtype = applicableSubtypes.get(i);
- if (subtype.containsExtraValueKey(TAG_ASCII_CAPABLE)) {
- hasAsciiCapableKeyboard = true;
- break;
+ if (!applicableSubtypes.isEmpty()) {
+ boolean hasAsciiCapableKeyboard = false;
+ final int numApplicationSubtypes = applicableSubtypes.size();
+ for (int i = 0; i < numApplicationSubtypes; ++i) {
+ final InputMethodSubtype subtype = applicableSubtypes.get(i);
+ if (subtype.containsExtraValueKey(TAG_ASCII_CAPABLE)) {
+ hasAsciiCapableKeyboard = true;
+ break;
+ }
}
- }
- if (!hasAsciiCapableKeyboard) {
- final int numKeyboardSubtypes = keyboardSubtypes.size();
- for (int i = 0; i < numKeyboardSubtypes; ++i) {
- final InputMethodSubtype subtype = keyboardSubtypes.get(i);
- final String mode = subtype.getMode();
- if (SUBTYPE_MODE_KEYBOARD.equals(mode) && subtype.containsExtraValueKey(
- TAG_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)) {
- applicableSubtypes.add(subtype);
+ if (!hasAsciiCapableKeyboard) {
+ final int numKeyboardSubtypes = keyboardSubtypes.size();
+ for (int i = 0; i < numKeyboardSubtypes; ++i) {
+ final InputMethodSubtype subtype = keyboardSubtypes.get(i);
+ final String mode = subtype.getMode();
+ if (SUBTYPE_MODE_KEYBOARD.equals(mode) && subtype.containsExtraValueKey(
+ TAG_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)) {
+ applicableSubtypes.add(subtype);
+ }
}
}
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index eb509c2..3abea26 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -499,11 +499,11 @@
try {
for (String classPathElement : classPathElements) {
+ // System server is fully AOTed and never profiled
+ // for profile guided compilation.
final int dexoptNeeded = DexFile.getDexOptNeeded(
- classPathElement, "*", instructionSet, false /* defer */);
+ classPathElement, instructionSet, DexFile.COMPILATION_TYPE_FULL);
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
- // System server is fully AOTed and never profiled
- // for profile guided compilation.
installer.dexopt(classPathElement, Process.SYSTEM_UID, instructionSet,
dexoptNeeded, 0 /*dexFlags*/, null /*volumeUuid*/,
false /*useProfiles*/);
diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java
index c4ed2e1..78c5e34 100644
--- a/core/java/com/android/internal/widget/ImageFloatingTextView.java
+++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java
@@ -65,6 +65,8 @@
.setTextDirection(getTextDirectionHeuristic())
.setLineSpacing(getLineSpacingExtra(), getLineSpacingMultiplier())
.setIncludePad(getIncludeFontPadding())
+ .setEllipsize(shouldEllipsize ? effectiveEllipsize : null)
+ .setEllipsizedWidth(ellipsisWidth)
.setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
// we set the endmargin on the first 2 lines. this works just in our case but that's
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index ed3fe42..623b603 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -7,7 +7,7 @@
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CFLAGS += -Wno-non-virtual-dtor
LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
-#LOCAL_CFLAGS += -DHWUI_NEW_OPS
+LOCAL_CFLAGS += -DHWUI_NEW_OPS
LOCAL_CPPFLAGS += -Wno-conversion-null
ifeq ($(TARGET_ARCH), arm)
@@ -190,7 +190,6 @@
$(call include-path-for, bluedroid) \
$(call include-path-for, libhardware)/hardware \
$(call include-path-for, libhardware_legacy)/hardware_legacy \
- $(TOP)/frameworks/av/include \
$(TOP)/frameworks/base/media/jni \
$(TOP)/system/core/base/include \
$(TOP)/system/core/include \
diff --git a/core/jni/android_app_Activity.cpp b/core/jni/android_app_Activity.cpp
index b1d7e82..56f4f01 100644
--- a/core/jni/android_app_Activity.cpp
+++ b/core/jni/android_app_Activity.cpp
@@ -15,16 +15,25 @@
*/
#include <poll.h>
-#include <android/dlext.h>
+
+#include <string>
#include "core_jni_helpers.h"
+extern "C" void android_dlwarning(void*, void (*)(void*, const char*));
+
namespace android
{
static jstring getDlWarning_native(JNIEnv* env, jobject) {
- const char* text = android_dlwarning();
- return text == nullptr ? nullptr : env->NewStringUTF(text);
+ std::string msg;
+ android_dlwarning(&msg, [](void* obj, const char* msg) {
+ if (msg != nullptr) {
+ *reinterpret_cast<std::string*>(obj) = msg;
+ }
+ });
+
+ return msg.empty() ? nullptr : env->NewStringUTF(msg.c_str());
}
static const JNINativeMethod g_methods[] = {
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 7930027..f37fd78 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -33,9 +33,9 @@
#include "core_jni_helpers.h"
#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
+#include <android/hardware/ICameraService.h>
#include <binder/IServiceManager.h>
#include <camera/CameraMetadata.h>
-#include <camera/ICameraService.h>
#include <camera/VendorTagDescriptor.h>
#include <nativehelper/ScopedUtfChars.h>
#include <nativehelper/ScopedPrimitiveArray.h>
@@ -906,32 +906,35 @@
static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
const String16 NAME("media.camera");
- sp<ICameraService> cameraService;
+ sp<hardware::ICameraService> cameraService;
status_t err = getService(NAME, /*out*/&cameraService);
if (err != OK) {
ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
strerror(-err), err);
- return err;
+ return hardware::ICameraService::ERROR_DISCONNECTED;
}
- sp<VendorTagDescriptor> desc;
- err = cameraService->getCameraVendorTagDescriptor(/*out*/desc);
+ sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
+ binder::Status res = cameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
- if (err == -EOPNOTSUPP) {
- ALOGW("%s: Camera HAL too old; does not support vendor tags", __FUNCTION__);
+ if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
+ // No camera module available, not an error on devices with no cameras
VendorTagDescriptor::clearGlobalVendorTagDescriptor();
-
return OK;
- } else if (err != OK) {
- ALOGE("%s: Failed to setup vendor tag descriptors, received error %s (%d)",
- __FUNCTION__, strerror(-err), err);
- return err;
+ } else if (!res.isOk()) {
+ VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+ ALOGE("%s: Failed to setup vendor tag descriptors: %s",
+ __FUNCTION__, res.toString8().string());
+ return res.serviceSpecificErrorCode();
}
err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
- return err;
+ if (err != OK) {
+ return hardware::ICameraService::ERROR_INVALID_OPERATION;
+ }
+ return OK;
}
} // extern "C"
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index cb0abb6..c6baf1c 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -80,6 +80,13 @@
return nullptr; \
}
+#define BAIL_IF_EXPR_RET_NULL_SP(expr, jnienv, tagId, writer) \
+ if (expr) { \
+ jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
+ "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
+ return nullptr; \
+ }
+
#define ANDROID_DNGCREATOR_CTX_JNI_ID "mNativeContext"
@@ -195,8 +202,8 @@
NativeContext::NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result) :
mCharacteristics(std::make_shared<CameraMetadata>(characteristics)),
mResult(std::make_shared<CameraMetadata>(result)), mThumbnailWidth(0),
- mThumbnailHeight(0), mOrientation(0), mThumbnailSet(false), mGpsSet(false),
- mDescriptionSet(false), mCaptureTimeSet(false) {}
+ mThumbnailHeight(0), mOrientation(TAG_ORIENTATION_UNKNOWN), mThumbnailSet(false),
+ mGpsSet(false), mDescriptionSet(false), mCaptureTimeSet(false) {}
NativeContext::~NativeContext() {}
@@ -1096,7 +1103,7 @@
{
// Set orientation
- uint16_t orientation = 1; // Normal
+ uint16_t orientation = TAG_ORIENTATION_NORMAL;
BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0),
env, TAG_ORIENTATION, writer);
}
@@ -1138,12 +1145,27 @@
}
{
- // Set blacklevel tags
+ // Set blacklevel tags, using dynamic black level if available
camera_metadata_entry entry =
- characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN);
- BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_BLACKLEVEL, writer);
- const uint32_t* blackLevel = reinterpret_cast<const uint32_t*>(entry.data.i32);
- BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel,
+ results.find(ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL);
+ uint32_t blackLevelRational[8] = {0};
+ if (entry.count != 0) {
+ BAIL_IF_EXPR_RET_NULL_SP(entry.count != 4, env, TAG_BLACKLEVEL, writer);
+ for (size_t i = 0; i < entry.count; i++) {
+ blackLevelRational[i * 2] = static_cast<uint32_t>(entry.data.f[i] * 100);
+ blackLevelRational[i * 2 + 1] = 100;
+ }
+ } else {
+ // Fall back to static black level which is guaranteed
+ entry = characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN);
+ BAIL_IF_EXPR_RET_NULL_SP(entry.count != 4, env, TAG_BLACKLEVEL, writer);
+ for (size_t i = 0; i < entry.count; i++) {
+ blackLevelRational[i * 2] = static_cast<uint32_t>(entry.data.i32[i]);
+ blackLevelRational[i * 2 + 1] = 1;
+ }
+
+ }
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVEL, 4, blackLevelRational,
TIFF_IFD_0), env, TAG_BLACKLEVEL, writer);
uint16_t repeatDim[2] = {2, 2};
@@ -1913,8 +1935,10 @@
{
// Set bits per sample
- uint16_t bits = BITS_PER_RGB_SAMPLE;
- BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0),
+ uint16_t bits[SAMPLES_PER_RGB_PIXEL];
+ for (int i = 0; i < SAMPLES_PER_RGB_PIXEL; i++) bits[i] = BITS_PER_RGB_SAMPLE;
+ BAIL_IF_INVALID_RET_NULL_SP(
+ writer->addEntry(TAG_BITSPERSAMPLE, SAMPLES_PER_RGB_PIXEL, bits, TIFF_IFD_0),
env, TAG_BITSPERSAMPLE, writer);
}
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index f1ea7ec..80f9d57 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -29,6 +29,7 @@
#include <gui/Surface.h>
#include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
#include <ui/GraphicBuffer.h>
#include <system/window.h>
#include <hardware/camera3.h>
@@ -93,27 +94,17 @@
cStep, yStride, cStride);
}
-static status_t configureSurface(const sp<ANativeWindow>& anw,
- int32_t width,
- int32_t height,
- int32_t pixelFmt,
- int32_t maxBufferSlack) {
+static status_t connectSurface(const sp<Surface>& surface, int32_t maxBufferSlack) {
status_t err = NO_ERROR;
- err = native_window_set_buffers_dimensions(anw.get(), width, height);
- if (err != NO_ERROR) {
- ALOGE("%s: Failed to set native window buffer dimensions, error %s (%d).", __FUNCTION__,
+
+ err = surface->connect(NATIVE_WINDOW_API_CAMERA, /*listener*/NULL);
+ if (err != OK) {
+ ALOGE("%s: Unable to connect to surface, error %s (%d).", __FUNCTION__,
strerror(-err), err);
return err;
}
- err = native_window_set_buffers_format(anw.get(), pixelFmt);
- if (err != NO_ERROR) {
- ALOGE("%s: Failed to set native window buffer format, error %s (%d).", __FUNCTION__,
- strerror(-err), err);
- return err;
- }
-
- err = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
+ err = native_window_set_usage(surface.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
if (err != NO_ERROR) {
ALOGE("%s: Failed to set native window usage flag, error %s (%d).", __FUNCTION__,
strerror(-err), err);
@@ -121,19 +112,17 @@
}
int minUndequeuedBuffers;
- err = anw.get()->query(anw.get(),
- NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
- &minUndequeuedBuffers);
+ err = static_cast<ANativeWindow*>(surface.get())->query(surface.get(),
+ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers);
if (err != NO_ERROR) {
ALOGE("%s: Failed to get native window min undequeued buffers, error %s (%d).",
__FUNCTION__, strerror(-err), err);
return err;
}
- ALOGV("%s: Setting buffer count to %d, size to (%dx%d), fmt (0x%x)", __FUNCTION__,
- maxBufferSlack + 1 + minUndequeuedBuffers,
- width, height, pixelFmt);
- err = native_window_set_buffer_count(anw.get(), maxBufferSlack + 1 + minUndequeuedBuffers);
+ ALOGV("%s: Setting buffer count to %d", __FUNCTION__,
+ maxBufferSlack + 1 + minUndequeuedBuffers);
+ err = native_window_set_buffer_count(surface.get(), maxBufferSlack + 1 + minUndequeuedBuffers);
if (err != NO_ERROR) {
ALOGE("%s: Failed to set native window buffer count, error %s (%d).", __FUNCTION__,
strerror(-err), err);
@@ -509,6 +498,26 @@
return usage;
}
+static jint LegacyCameraDevice_nativeDisconnectSurface(JNIEnv* env, jobject thiz,
+ jobject surface) {
+ ALOGV("nativeDisconnectSurface");
+ if (surface == nullptr) return NO_ERROR;
+
+ sp<ANativeWindow> anw;
+ if ((anw = getNativeWindow(env, surface)) == NULL) {
+ ALOGV("Buffer queue has already been abandoned.");
+ return NO_ERROR;
+ }
+
+ status_t err = native_window_api_disconnect(anw.get(), NATIVE_WINDOW_API_CAMERA);
+ if(err != NO_ERROR) {
+ jniThrowException(env, "Ljava/lang/UnsupportedOperationException;",
+ "Error while disconnecting surface");
+ return err;
+ }
+ return NO_ERROR;
+}
+
static jint LegacyCameraDevice_nativeDetectTextureDimens(JNIEnv* env, jobject thiz,
jobject surfaceTexture, jintArray dimens) {
ALOGV("nativeDetectTextureDimens");
@@ -540,15 +549,14 @@
return NO_ERROR;
}
-static jint LegacyCameraDevice_nativeConfigureSurface(JNIEnv* env, jobject thiz, jobject surface,
- jint width, jint height, jint pixelFormat) {
- ALOGV("nativeConfigureSurface");
- sp<ANativeWindow> anw;
- if ((anw = getNativeWindow(env, surface)) == NULL) {
- ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
+static jint LegacyCameraDevice_nativeConnectSurface(JNIEnv* env, jobject thiz, jobject surface) {
+ ALOGV("nativeConnectSurface");
+ sp<Surface> s;
+ if ((s = getSurface(env, surface)) == NULL) {
+ ALOGE("%s: Could not retrieve surface.", __FUNCTION__);
return BAD_VALUE;
}
- status_t err = configureSurface(anw, width, height, pixelFormat, CAMERA_DEVICE_BUFFER_SLACK);
+ status_t err = connectSurface(s, CAMERA_DEVICE_BUFFER_SLACK);
if (err != NO_ERROR) {
ALOGE("%s: Error while configuring surface %s (%d).", __FUNCTION__, strerror(-err), err);
return err;
@@ -740,9 +748,9 @@
{ "nativeDetectSurfaceDimens",
"(Landroid/view/Surface;[I)I",
(void *)LegacyCameraDevice_nativeDetectSurfaceDimens },
- { "nativeConfigureSurface",
- "(Landroid/view/Surface;III)I",
- (void *)LegacyCameraDevice_nativeConfigureSurface },
+ { "nativeConnectSurface",
+ "(Landroid/view/Surface;)I",
+ (void *)LegacyCameraDevice_nativeConnectSurface },
{ "nativeProduceFrame",
"(Landroid/view/Surface;[BIII)I",
(void *)LegacyCameraDevice_nativeProduceFrame },
@@ -773,6 +781,9 @@
{ "nativeSetScalingMode",
"(Landroid/view/Surface;I)I",
(void *)LegacyCameraDevice_nativeSetScalingMode },
+ { "nativeDisconnectSurface",
+ "(Landroid/view/Surface;)I",
+ (void *)LegacyCameraDevice_nativeDisconnectSurface },
};
// Get all the required offsets in java class and register native functions
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index defb88a..880a79c 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -26,10 +26,13 @@
#include <net/if.h>
#include <linux/filter.h>
#include <linux/if.h>
+#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <net/if_ether.h>
+#include <netinet/icmp6.h>
#include <netinet/ip.h>
+#include <netinet/ip6.h>
#include <netinet/udp.h>
#include <cutils/properties.h>
@@ -64,10 +67,9 @@
static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd)
{
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
uint32_t ip_offset = sizeof(ether_header);
uint32_t proto_offset = ip_offset + offsetof(iphdr, protocol);
- uint32_t flags_offset = ip_offset + offsetof(iphdr, frag_off);
+ uint32_t flags_offset = ip_offset + offsetof(iphdr, frag_off);
uint32_t dport_indirect_offset = ip_offset + offsetof(udphdr, dest);
struct sock_filter filter_code[] = {
// Check the protocol is UDP.
@@ -94,6 +96,45 @@
filter_code,
};
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
+ }
+}
+
+static void android_net_utils_attachRaFilter(JNIEnv *env, jobject clazz, jobject javaFd,
+ jint hardwareAddressType)
+{
+ if (hardwareAddressType != ARPHRD_ETHER) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "attachRaFilter only supports ARPHRD_ETHER");
+ return;
+ }
+
+ uint32_t ipv6_offset = sizeof(ether_header);
+ uint32_t ipv6_next_header_offset = ipv6_offset + offsetof(ip6_hdr, ip6_nxt);
+ uint32_t icmp6_offset = ipv6_offset + sizeof(ip6_hdr);
+ uint32_t icmp6_type_offset = icmp6_offset + offsetof(icmp6_hdr, icmp6_type);
+ struct sock_filter filter_code[] = {
+ // Check IPv6 Next Header is ICMPv6.
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, ipv6_next_header_offset),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3),
+
+ // Check ICMPv6 type is Router Advertisement.
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, icmp6_type_offset),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_ROUTER_ADVERT, 0, 1),
+
+ // Accept or reject.
+ BPF_STMT(BPF_RET | BPF_K, 0xffff),
+ BPF_STMT(BPF_RET | BPF_K, 0)
+ };
+ struct sock_fprog filter = {
+ sizeof(filter_code) / sizeof(filter_code[0]),
+ filter_code,
+ };
+
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
jniThrowExceptionFmt(env, "java/net/SocketException",
"setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
@@ -148,6 +189,7 @@
{ "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn },
{ "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
{ "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter },
+ { "attachRaFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachRaFilter },
};
int register_android_net_NetworkUtils(JNIEnv* env)
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 3df0876..f870a89 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -262,7 +262,13 @@
}
name = line + name_pos;
nameLen = strlen(name);
-
+ // Trim the end of the line if it is " (deleted)".
+ const char* deleted_str = " (deleted)";
+ if (nameLen > (int)strlen(deleted_str) &&
+ strcmp(name+nameLen-strlen(deleted_str), deleted_str) == 0) {
+ nameLen -= strlen(deleted_str);
+ name[nameLen] = '\0';
+ }
if ((strstr(name, "[heap]") == name)) {
whichHeap = HEAP_NATIVE;
} else if (strncmp(name, "[anon:libc_malloc]", 18) == 0) {
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index cf68449..b7701d6 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -411,22 +411,27 @@
return 0;
}
+ android::view::Surface surfaceShim;
+
+ // Calling code in Surface.java has already read the name of the Surface
+ // from the Parcel
+ surfaceShim.readFromParcel(parcel, /*nameAlreadyRead*/true);
+
sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
- sp<IBinder> binder(parcel->readStrongBinder());
// update the Surface only if the underlying IGraphicBufferProducer
// has changed.
- if (self != NULL
- && (IInterface::asBinder(self->getIGraphicBufferProducer()) == binder)) {
+ if (self != nullptr
+ && (IInterface::asBinder(self->getIGraphicBufferProducer()) ==
+ IInterface::asBinder(surfaceShim.graphicBufferProducer))) {
// same IGraphicBufferProducer, return ourselves
return jlong(self.get());
}
sp<Surface> sur;
- sp<IGraphicBufferProducer> gbp(interface_cast<IGraphicBufferProducer>(binder));
- if (gbp != NULL) {
+ if (surfaceShim.graphicBufferProducer != nullptr) {
// we have a new IGraphicBufferProducer, create a new Surface for it
- sur = new Surface(gbp, true);
+ sur = new Surface(surfaceShim.graphicBufferProducer, true);
// and keep a reference before passing to java
sur->incStrong(&sRefBaseOwner);
}
@@ -447,7 +452,13 @@
return;
}
sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
- parcel->writeStrongBinder( self != 0 ? IInterface::asBinder(self->getIGraphicBufferProducer()) : NULL);
+ android::view::Surface surfaceShim;
+ if (self != nullptr) {
+ surfaceShim.graphicBufferProducer = self->getIGraphicBufferProducer();
+ }
+ // Calling code in Surface.java has already written the name of the Surface
+ // to the Parcel
+ surfaceShim.writeToParcel(parcel, /*nameAlreadyWritten*/true);
}
static jint nativeGetWidth(JNIEnv* env, jclass clazz, jlong nativeObject) {
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 1dfe40a..c838d03 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -110,6 +110,13 @@
ctrl->decStrong((void *)nativeCreate);
}
+static void nativeDisconnect(JNIEnv* env, jclass clazz, jlong nativeObject) {
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ if (ctrl != NULL) {
+ ctrl->disconnect();
+ }
+}
+
static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz,
jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform,
@@ -595,6 +602,8 @@
(void*)nativeRelease },
{"nativeDestroy", "(J)V",
(void*)nativeDestroy },
+ {"nativeDisconnect", "(J)V",
+ (void*)nativeDisconnect },
{"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/Bitmap;",
(void*)nativeScreenshotBitmap },
{"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;IIIIZZ)V",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 588e738..8f85d4a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -87,6 +87,7 @@
<protected-broadcast android:name="android.os.action.DEVICE_IDLE_MODE_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_WHITELIST_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED" />
+ <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED_INTERNAL" />
<protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
@@ -265,6 +266,7 @@
<protected-broadcast android:name="com.android.server.WifiManager.action.START_SCAN" />
<protected-broadcast android:name="com.android.server.WifiManager.action.START_PNO" />
<protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" />
+ <protected-broadcast android:name="com.android.server.WifiManager.action.DEVICE_IDLE" />
<protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED" />
<protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED" />
<protected-broadcast android:name="android.net.wifi.WIFI_STATE_CHANGED" />
@@ -374,7 +376,10 @@
<protected-broadcast android:name="android.app.action.ACTION_PASSWORD_FAILED" />
<protected-broadcast android:name="android.app.action.ACTION_PASSWORD_SUCCEEDED" />
<protected-broadcast android:name="com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION" />
+
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_ADDED" />
+ <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
+ <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_REMOVED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.BLE_STATE_CHANGED" />
<protected-broadcast android:name="android.content.jobscheduler.JOB_DELAY_EXPIRED" />
@@ -432,7 +437,6 @@
<protected-broadcast android:name="android.intent.action.DYNAMIC_SENSOR_CHANGED" />
<protected-broadcast android:name="android.intent.action.ACTION_RADIO_OFF" />
- <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
<protected-broadcast android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
<protected-broadcast android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" />
@@ -450,6 +454,10 @@
<protected-broadcast android:name="android.intent.action.TWILIGHT_CHANGED" />
+ <protected-broadcast android:name="com.android.server.fingerprint.ACTION_LOCKOUT_RESET" />
+ <protected-broadcast android:name="android.net.wifi.PASSPOINT_ICON_RECEIVED" />
+ <protected-broadcast android:name="com.android.server.notification.CountdownConditionProvider" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
diff --git a/core/res/res/drawable-nodpi/default_wallpaper.png b/core/res/res/drawable-nodpi/default_wallpaper.png
index 91ad252..e9c4d5c 100644
--- a/core/res/res/drawable-nodpi/default_wallpaper.png
+++ b/core/res/res/drawable-nodpi/default_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png
index af8e251..9f3efa5 100644
--- a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png
+++ b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png
index cb00d82..8199e70 100644
--- a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png
+++ b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png
Binary files differ
diff --git a/core/res/res/layout/notification_template_material_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml
index 9a4b28c..3c59b4e 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -39,7 +39,7 @@
<com.android.internal.widget.ImageFloatingTextView android:id="@+id/big_text"
android:layout_width="match_parent"
android:layout_height="0dp"
- android:layout_marginTop="1.5dp"
+ android:layout_marginTop="1dp"
android:paddingBottom="@dimen/notification_content_margin_bottom"
android:textAppearance="@style/TextAppearance.Material.Notification"
android:singleLine="false"
diff --git a/core/res/res/layout/notification_template_text.xml b/core/res/res/layout/notification_template_text.xml
index 38470cd..47b30ec 100644
--- a/core/res/res/layout/notification_template_text.xml
+++ b/core/res/res/layout/notification_template_text.xml
@@ -14,12 +14,12 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.internal.widget.ImageFloatingTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
- android:layout_marginTop="1.5dp"
+ android:layout_marginTop="1dp"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:gravity="top"
diff --git a/core/res/res/layout/text_edit_suggestion_container_material.xml b/core/res/res/layout/text_edit_suggestion_container_material.xml
index 15b18dd..d1c65c0 100644
--- a/core/res/res/layout/text_edit_suggestion_container_material.xml
+++ b/core/res/res/layout/text_edit_suggestion_container_material.xml
@@ -33,7 +33,7 @@
android:id="@+id/suggestionContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="8dp"
+ android:paddingTop="4dp"
android:paddingBottom="0dp"
android:divider="@null" />
<LinearLayout
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b65f19b..7857107 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -443,6 +443,9 @@
<!-- Boolean indicating whether or not wifi firmware debugging is enabled -->
<bool translatable="false" name="config_wifi_enable_wifi_firmware_debugging">true</bool>
+ <!-- Integer size limit, in KB, for a single WifiLogger ringbuffer -->
+ <integer translatable="false" name="config_wifi_logger_ring_buffer_size_limit_kb">32</integer>
+
<!-- Boolean indicating whether or not wifi should turn off when emergency call is made -->
<bool translatable="false" name="config_wifi_turn_off_during_emergency_call">false</bool>
@@ -2437,6 +2440,10 @@
flag). -->
<bool name="config_forceWindowDrawsStatusBarBackground">true</bool>
+ <!-- If set, this will force the navigation bar to always be drawn with an opaque
+ background. -->
+ <bool name="config_forceNavBarAlwaysOpaque">false</bool>
+
<!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. -->
<string translatable="false" name="config_defaultPictureInPictureBounds">"0 0 100 100"</string>
@@ -2479,4 +2486,8 @@
handle wallpaper cropping.
-->
<string name="config_wallpaperCropperPackage" translatable="false">com.android.wallpapercropper</string>
+
+ <!-- True if the device supports at least one form of multi-window.
+ E.g. freeform, split-screen, picture-in-picture. -->
+ <bool name="config_supportsMultiWindow">true</bool>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7b11302..d8efd63 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2917,20 +2917,18 @@
<!-- Message of notification shown when ADB is actively connected to the phone. -->
<string name="adb_active_notification_message">Touch to disable USB debugging.</string>
+ <!-- Title of notification shown to indicate that bug report is being collected. -->
+ <string name="taking_remote_bugreport_notification_title">Taking bug report\u2026</string>
<!-- Title of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
<string name="share_remote_bugreport_notification_title">Share bug report?</string>
<!-- Title of notification shown to indicate that bug report is still being collected after sharing was accepted. -->
<string name="sharing_remote_bugreport_notification_title">Sharing bug report\u2026</string>
- <!-- Message of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
- <string name="share_remote_bugreport_notification_message">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared and your device may temporarily slow down.</string>
- <!-- Message of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
- <string name="share_finished_remote_bugreport_notification_message">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared.</string>
- <!-- Message of notification shown to shown to indicate that bug report is still being collected after sharing was accepted. -->
- <string name="sharing_remote_bugreport_notification_message">This may temporarily slow down your device</string>
+ <!-- Message of a notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
+ <string name="share_remote_bugreport_notification_message_finished">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared.</string>
<!-- Acceptance label of notification shown to ask for user consent for sharing the remote bugreport. -->
- <string name="share_remote_bugreport_notification_accept">ACCEPT</string>
+ <string name="share_remote_bugreport_action">SHARE</string>
<!-- Decline label of notification shown to ask for user consent for sharing the remote bugreport. -->
- <string name="share_remote_bugreport_notification_decline">DECLINE</string>
+ <string name="decline_remote_bugreport_action">DECLINE</string>
<!-- Used to replace %s in urls retreived from the signin server with locales. For Some -->
<!-- devices we don't support all the locales we ship to and need to replace the '%s' with a -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index eba2e6a..15521e4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -298,11 +298,13 @@
<java-symbol type="bool" name="config_wifi_enable_5GHz_preference" />
<java-symbol type="bool" name="config_wifi_revert_country_code_on_cellular_loss" />
<java-symbol type="bool" name="config_wifi_enable_wifi_firmware_debugging" />
+ <java-symbol type="integer" name="config_wifi_logger_ring_buffer_size_limit_kb" />
<java-symbol type="bool" name="config_wifi_turn_off_during_emergency_call" />
<java-symbol type="bool" name="config_supportMicNearUltrasound" />
<java-symbol type="bool" name="config_supportSpeakerNearUltrasound" />
<java-symbol type="bool" name="config_supportAudioSourceUnprocessed" />
<java-symbol type="bool" name="config_freeformWindowManagement" />
+ <java-symbol type="bool" name="config_supportsMultiWindow" />
<java-symbol type="bool" name="config_guestUserEphemeral" />
<java-symbol type="string" name="config_defaultPictureInPictureBounds" />
<java-symbol type="string" name="config_centeredPictureInPictureBounds" />
@@ -1769,13 +1771,12 @@
<java-symbol type="string" name="accessibility_binding_label" />
<java-symbol type="string" name="adb_active_notification_message" />
<java-symbol type="string" name="adb_active_notification_title" />
+ <java-symbol type="string" name="taking_remote_bugreport_notification_title" />
<java-symbol type="string" name="share_remote_bugreport_notification_title" />
- <java-symbol type="string" name="share_remote_bugreport_notification_message" />
- <java-symbol type="string" name="share_finished_remote_bugreport_notification_message" />
<java-symbol type="string" name="sharing_remote_bugreport_notification_title" />
- <java-symbol type="string" name="sharing_remote_bugreport_notification_message" />
- <java-symbol type="string" name="share_remote_bugreport_notification_accept" />
- <java-symbol type="string" name="share_remote_bugreport_notification_decline" />
+ <java-symbol type="string" name="share_remote_bugreport_notification_message_finished" />
+ <java-symbol type="string" name="share_remote_bugreport_action" />
+ <java-symbol type="string" name="decline_remote_bugreport_action" />
<java-symbol type="string" name="aerr_application" />
<java-symbol type="string" name="aerr_process" />
<java-symbol type="string" name="aerr_application_repeated" />
@@ -2390,6 +2391,7 @@
<java-symbol type="string" name="config_packagedKeyboardName" />
<java-symbol type="bool" name="config_forceWindowDrawsStatusBarBackground" />
+ <java-symbol type="bool" name="config_forceNavBarAlwaysOpaque" />
<java-symbol type="color" name="system_bar_background_semi_transparent" />
<!-- EditText suggestion popup. -->
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
index 998c72a..c92863d 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
@@ -328,7 +328,12 @@
// Only a1's pause listener should be called.
assertTrue(l1.pauseCalled);
assertFalse(l1.resumeCalled);
- a1.resume();
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ a1.resume();
+ }
+ });
Thread.sleep(a1.getTotalDuration());
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
index e9fd5fb..5d46489 100644
--- a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
+++ b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
@@ -38,7 +38,7 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mCache = new ConfigurationBoundResourceCache<Float>(getActivity().getResources());
+ mCache = new ConfigurationBoundResourceCache<>();
}
public void testGetEmpty() {
diff --git a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
new file mode 100644
index 0000000..da17045
--- /dev/null
+++ b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2016 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.text.method;
+
+import android.app.Activity;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.text.InputType;
+import android.text.method.BaseKeyListener;
+import android.text.method.KeyListenerTestCase;
+import android.view.KeyEvent;
+import android.widget.EditText;
+import android.widget.TextView.BufferType;
+
+/**
+ * Test forward delete key handling of {@link android.text.method.BaseKeyListener}.
+ *
+ * TODO: Move some of test cases to the CTS.
+ */
+public class ForwardDeleteTest extends KeyListenerTestCase {
+ private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
+ public int getInputType() {
+ return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+ }
+ };
+
+ // Sync the state to the TextView and call onKeyDown with KEYCODE_FORWARD_DEL key event.
+ // Then update the state to the result of TextView.
+ private void forwardDelete(final EditorState state, int modifiers) {
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mTextView.setText(state.mText, BufferType.EDITABLE);
+ mTextView.setKeyListener(mKeyListener);
+ mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ assertTrue(mTextView.hasWindowFocus());
+
+ final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_FORWARD_DEL, modifiers);
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ state.mText = mTextView.getText();
+ state.mSelectionStart = mTextView.getSelectionStart();
+ state.mSelectionEnd = mTextView.getSelectionEnd();
+ }
+
+ @SmallTest
+ public void testSurrogatePairs() {
+ EditorState state = new EditorState();
+
+ // U+1F441 is EYE
+ state.setByString("| U+1F441");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // U+1F5E8 is LEFT SPEECH BUBBLE
+ state.setByString("| U+1F441 U+1F5E8");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F5E8");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // TODO: introduce edge cases.
+ }
+
+ @SmallTest
+ public void testReplacementSpan() {
+ EditorState state = new EditorState();
+
+ state.setByString("| 'abc' ( 'de' ) 'fg'");
+ forwardDelete(state, 0);
+ state.assertEquals("| 'bc' ( 'de' ) 'fg'");
+ forwardDelete(state, 0);
+ state.assertEquals("| 'c' ( 'de' ) 'fg'");
+ forwardDelete(state, 0);
+ state.assertEquals("| ( 'de' ) 'fg'");
+ forwardDelete(state, 0);
+ state.assertEquals("| 'fg'");
+ forwardDelete(state, 0);
+ state.assertEquals("| 'g'");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("'abc' [ ( 'de' ) ] 'fg'");
+ forwardDelete(state, 0);
+ state.assertEquals("'abc' | 'fg'");
+ forwardDelete(state, 0);
+ state.assertEquals("'abc' | 'g'");
+ forwardDelete(state, 0);
+ state.assertEquals("'abc' |");
+ forwardDelete(state, 0);
+ state.assertEquals("'abc' |");
+
+ state.setByString("'ab' [ 'c' ( 'de' ) 'f' ] 'g'");
+ forwardDelete(state, 0);
+ state.assertEquals("'ab' | 'g'");
+ forwardDelete(state, 0);
+ state.assertEquals("'ab' |");
+ forwardDelete(state, 0);
+ state.assertEquals("'ab' |");
+
+ // TODO: introduce edge cases.
+ }
+
+ @SmallTest
+ public void testCombiningEnclosingKeycaps() {
+ EditorState state = new EditorState();
+
+ // U+20E3 is COMBINING ENCLOSING KEYCAP.
+ state.setByString("| '1' U+20E3");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Edge cases
+ // multiple COMBINING ENCLOSING KEYCAP
+ state.setByString("| '1' U+20E3 U+20E3");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Isolated COMBINING ENCLOSING KEYCAP
+ state.setByString("| U+20E3");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Isolated multiple COMBINING ENCLOSING KEYCAP
+ state.setByString("| U+20E3 U+20E3");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
+ public void testVariationSelector() {
+ EditorState state = new EditorState();
+
+ // U+FE0F is VARIATION SELECTOR-16.
+ state.setByString("| '#' U+FE0F");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // U+E0100 is VARIATION SELECTOR-17.
+ state.setByString("| U+845B U+E0100");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Edge cases
+ // Isolated variation selectors
+ state.setByString("| U+FE0F");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("| U+E0100");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Isolated multiple variation selectors
+ state.setByString("| U+FE0F U+FE0F");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("| U+FE0F U+E0100");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("| U+E0100 U+FE0F");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("| U+E0100 U+E0100");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Multiple variation selectors
+ state.setByString("| '#' U+FE0F U+FE0F");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("| '#' U+FE0F U+E0100");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("| U+845B U+E0100 U+FE0F");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("| U+845B U+E0100 U+E0100");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
+ public void testEmojiZeroWidthJoinerSequence() {
+ EditorState state = new EditorState();
+
+ // U+200D is ZERO WIDTH JOINER.
+ state.setByString("| U+1F441 U+200D U+1F5E8");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("| U+1F468 U+200D U+2764 U+FE0F U+200D U+1F48B U+200D U+1F468");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Edge cases
+ // End with ZERO WIDTH JOINER
+ state.setByString("| U+1F441 U+200D");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Start with ZERO WIDTH JOINER
+ state.setByString("| U+200D U+1F5E8");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F5E8");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Multiple ZERO WIDTH JOINER
+ state.setByString("| U+1F441 U+200D U+200D U+1F5E8");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F5E8");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Isolated ZERO WIDTH JOINER
+ state.setByString("| U+200D");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Isolated multiple ZERO WIDTH JOINER
+ state.setByString("| U+200D U+200D");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
+ public void testFlags() {
+ EditorState state = new EditorState();
+
+ // U+1F1FA is REGIONAL INDICATOR SYMBOL LETTER U.
+ // U+1F1F8 is REGIONAL INDICATOR SYMBOL LETTER S.
+ state.setByString("| U+1F1FA U+1F1F8");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("| U+1F1FA U+1F1F8 U+1F1FA U+1F1F8");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F1FA U+1F1F8");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Edge cases
+ // Isolated regional indicator symbol
+ state.setByString("| U+1F1FA");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Odd numbered regional indicator symbols
+ state.setByString("| U+1F1FA U+1F1F8 U+1F1FA");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F1FA");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
+ public void testEmojiModifier() {
+ EditorState state = new EditorState();
+
+ // U+1F3FB is EMOJI MODIFIER FITZPATRICK TYPE-1-2.
+ state.setByString("| U+1F466 U+1F3FB");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Edge cases
+ // Isolated emoji modifier
+ state.setByString("| U+1F3FB");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Isolated multiple emoji modifier
+ state.setByString("| U+1F3FB U+1F3FB");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F3FB");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Multiple emoji modifiers
+ state.setByString("| U+1F466 U+1F3FB U+1F3FB");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F3FB");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
+ public void testMixedEdgeCases() {
+ EditorState state = new EditorState();
+
+ // COMBINING ENCLOSING KEYCAP + variation selector
+ state.setByString("| '1' U+20E3 U+FE0F");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Variation selector + COMBINING ENCLOSING KEYCAP
+ state.setByString("| U+2665 U+FE0F U+20E3");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // COMBINING ENCLOSING KEYCAP + ending with ZERO WIDTH JOINER
+ state.setByString("| '1' U+20E3 U+200D");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // COMBINING ENCLOSING KEYCAP + ZERO WIDTH JOINER
+ state.setByString("| '1' U+20E3 U+200D U+1F5E8");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F5E8 ");
+
+ // Start with ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP
+ state.setByString("| U+200D U+20E3");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP
+ state.setByString("| U+1F441 U+200D U+20E3");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // COMBINING ENCLOSING KEYCAP + regional indicator symbol
+ state.setByString("| '1' U+20E3 U+1F1FA");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F1FA");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Regional indicator symbol + COMBINING ENCLOSING KEYCAP
+ state.setByString("| U+1F1FA U+20E3");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // COMBINING ENCLOSING KEYCAP + emoji modifier
+ state.setByString("| '1' U+20E3 U+1F3FB");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F3FB");
+
+ // Emoji modifier + COMBINING ENCLOSING KEYCAP
+ state.setByString("| U+1F466 U+1F3FB U+20E3");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Variation selector + end with ZERO WIDTH JOINER
+ state.setByString("| U+2665 U+FE0F U+200D");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Variation selector + ZERO WIDTH JOINER
+ state.setByString("| U+1F469 U+200D U+2764 U+FE0F U+200D U+1F469");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Start with ZERO WIDTH JOINER + variation selector
+ state.setByString("| U+200D U+FE0F");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // ZERO WIDTH JOINER + variation selector
+ state.setByString("| U+1F469 U+200D U+FE0F");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Variation selector + regional indicator symbol
+ state.setByString("| U+2665 U+FE0F U+1F1FA");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F1FA");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Regional indicator symbol + variation selector
+ state.setByString("| U+1F1FA U+FE0F");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Variation selector + emoji modifier
+ state.setByString("| U+2665 U+FE0F U+1F3FB");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F3FB");
+
+ // Emoji modifier + variation selector
+ state.setByString("| U+1F466 U+1F3FB U+FE0F");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Start with ZERO WIDTH JOINER + regional indicator symbol
+ state.setByString("| U+200D U+1F1FA");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F1FA");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // ZERO WIDTH JOINER + regional indicator symbol
+ state.setByString("| U+1F469 U+200D U+1F1FA");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F1FA");
+
+ // Regional indicator symbol + end with ZERO WIDTH JOINER
+ state.setByString("| U+1F1FA U+200D");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Regional indicator symbol + ZERO WIDTH JOINER
+ state.setByString("| U+1F1FA U+200D U+1F469");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F469");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Start with ZERO WIDTH JOINER + emoji modifier
+ state.setByString("| U+200D U+1F3FB");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F3FB");
+
+ // ZERO WIDTH JOINER + emoji modifier
+ state.setByString("| U+1F469 U+200D U+1F3FB");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F3FB");
+
+ // Emoji modifier + end with ZERO WIDTH JOINER
+ state.setByString("| U+1F466 U+1F3FB U+200D");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Emoji modifier + ZERO WIDTH JOINER
+ state.setByString("| U+1F466 U+1F3FB U+200D U+1F469");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F469");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Regional indicator symbol + emoji modifier
+ state.setByString("| U+1F1FA U+1F3FB");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F3FB");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // Emoji modifier + regional indicator symbol
+ state.setByString("| U+1F466 U+1F3FB U+1F1FA");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+1F1FA");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+ }
+}
diff --git a/core/tests/coretests/src/android/util/PatternsTest.java b/core/tests/coretests/src/android/util/PatternsTest.java
index d383775..348f8fd 100644
--- a/core/tests/coretests/src/android/util/PatternsTest.java
+++ b/core/tests/coretests/src/android/util/PatternsTest.java
@@ -25,7 +25,7 @@
public class PatternsTest extends TestCase {
- //Tests for Patterns.TOP_LEVEL_DOMAIN
+ // Tests for Patterns.TOP_LEVEL_DOMAIN
@SmallTest
public void testTldPattern() throws Exception {
@@ -56,7 +56,7 @@
assertFalse("Matched invalid TLD!", t);
}
- //Tests for Patterns.IANA_TOP_LEVEL_DOMAINS
+ // Tests for Patterns.IANA_TOP_LEVEL_DOMAINS
@SmallTest
public void testIanaTopLevelDomains_matchesValidTld() throws Exception {
@@ -94,7 +94,7 @@
assertFalse("Should not match invalid Punycode TLD", pattern.matcher("xn").matches());
}
- //Tests for Patterns.WEB_URL
+ // Tests for Patterns.WEB_URL
@SmallTest
public void testWebUrl_matchesValidUrlWithSchemeAndHostname() throws Exception {
@@ -208,7 +208,7 @@
Patterns.WEB_URL.matcher(url).matches());
}
- //Tests for Patterns.AUTOLINK_WEB_URL
+ // Tests for Patterns.AUTOLINK_WEB_URL
@SmallTest
public void testAutoLinkWebUrl_matchesValidUrlWithSchemeAndHostname() throws Exception {
@@ -419,7 +419,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
- //Tests for Patterns.IP_ADDRESS
+ // Tests for Patterns.IP_ADDRESS
@SmallTest
public void testIpPattern() throws Exception {
@@ -432,7 +432,7 @@
assertFalse("Invalid IP", t);
}
- //Tests for Patterns.DOMAIN_NAME
+ // Tests for Patterns.DOMAIN_NAME
@SmallTest
public void testDomain_matchesPunycodeTld() throws Exception {
@@ -508,7 +508,227 @@
Patterns.DOMAIN_NAME.matcher(domain).matches());
}
- //Tests for Patterns.PHONE
+ // Tests for Patterns.AUTOLINK_EMAIL_ADDRESS
+
+ public void testAutoLinkEmailAddress_matchesShortValidEmail() throws Exception {
+ String email = "a@a.co";
+ assertTrue("Should match short valid email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesRegularEmail() throws Exception {
+ String email = "email@android.com";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesEmailWithMultipleSubdomains() throws Exception {
+ String email = "email@e.somelongdomainnameforandroid.abc.uk";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesLocalPartWithDot() throws Exception {
+ String email = "e.mail@android.com";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesLocalPartWithPlus() throws Exception {
+ String email = "e+mail@android.com";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesLocalPartWithUnderscore() throws Exception {
+ String email = "e_mail@android.com";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesLocalPartWithDash() throws Exception {
+ String email = "e-mail@android.com";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesLocalPartWithApostrophe() throws Exception {
+ String email = "e'mail@android.com";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesLocalPartWithDigits() throws Exception {
+ String email = "123@android.com";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesUnicodeLocalPart() throws Exception {
+ String email = "\uD604\uAE08\uC601\uC218\uC99D@android.kr";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesLocalPartWithEmoji() throws Exception {
+ String email = "smiley\u263A@android.com";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesLocalPartWithSurrogatePairs() throws Exception {
+ String email = "\uD83C\uDF38@android.com";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesDomainWithDash() throws Exception {
+ String email = "email@an-droid.com";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesUnicodeDomain() throws Exception {
+ String email = "email@\uD604\uAE08\uC601\uC218\uC99D.kr";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesUnicodeLocalPartAndDomain() throws Exception {
+ String email = "\uD604\uAE08\uC601\uC218\uC99D@\uD604\uAE08\uC601\uC218\uC99D.kr";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesDomainWithEmoji() throws Exception {
+ String email = "smiley@\u263Aandroid.com";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesDomainWithSurrogatePairs() throws Exception {
+ String email = "email@\uD83C\uDF38android.com";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesLocalPartAndDomainWithSurrogatePairs()
+ throws Exception {
+ String email = "\uD83C\uDF38@\uD83C\uDF38android.com";
+ assertTrue("Should match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_doesNotMatchStringWithoutAtSign() throws Exception {
+ String email = "android.com";
+ assertFalse("Should not match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_doesNotMatchPlainString() throws Exception {
+ String email = "email";
+ assertFalse("Should not match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_doesNotMatchStringWithMultipleAtSigns() throws Exception {
+ String email = "email@android@android.com";
+ assertFalse("Should not match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_doesNotMatchEmailWithoutTld() throws Exception {
+ String email = "email@android";
+ assertFalse("Should not match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_doesNotMatchLocalPartEndingWithDot() throws Exception {
+ String email = "email.@android.com";
+ assertFalse("Should not match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_doesNotMatchLocalPartStartingWithDot() throws Exception {
+ String email = ".email@android.com";
+ assertFalse("Should not match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_doesNotMatchDomainStartingWithDash() throws Exception {
+ String email = "email@-android.com";
+ assertFalse("Should not match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_doesNotMatchDomainWithConsecutiveDots() throws Exception {
+ String email = "email@android..com";
+ assertFalse("Should not match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_doesNotMatchEmailWithIpAsDomain() throws Exception {
+ String email = "email@127.0.0.1";
+ assertFalse("Should not match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_doesNotMatchEmailWithInvalidTld() throws Exception {
+ String email = "email@android.c";
+ assertFalse("Should not match email: " + email,
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesLocalPartUpTo64Chars() throws Exception {
+ String localPart = "";
+ for (int i = 0; i < 64; i++) {
+ localPart += "a";
+ }
+ String email = localPart + "@android.com";
+
+ assertTrue("Should match local part of length: " + localPart.length(),
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+
+ email = localPart + "a@android.com";
+ assertFalse("Should not match local part of length: " + localPart.length(),
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesSubdomainUpTo63Chars() throws Exception {
+ String subdomain = "";
+ for (int i = 0; i < 63; i++) {
+ subdomain += "a";
+ }
+ String email = "email@" + subdomain + ".com";
+
+ assertTrue("Should match subdomain of length: " + subdomain.length(),
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+
+ subdomain += "a";
+ email = "email@" + subdomain + ".com";
+ assertFalse("Should not match local part of length: " + subdomain.length(),
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ public void testAutoLinkEmailAddress_matchesDomainUpTo255Chars() throws Exception {
+ String longDomain = "";
+ while (longDomain.length() <= 250) {
+ longDomain += "d.";
+ }
+ longDomain += "com";
+ assertEquals(255, longDomain.length());
+ String email = "a@" + longDomain;
+
+ assertTrue("Should match domain of length: " + longDomain.length(),
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+
+ email = email + "m";
+ assertEquals(258, email.length());
+ assertFalse("Should not match domain of length: " + longDomain.length(),
+ Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+ }
+
+ // Tests for Patterns.PHONE
@SmallTest
public void testPhonePattern() throws Exception {
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
index ac020e4..719b274 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
@@ -70,6 +70,7 @@
private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH");
private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
private static final String SUBTYPE_MODE_VOICE = "voice";
+ private static final String SUBTYPE_MODE_HANDWRITING = "handwriting";
private static final String SUBTYPE_MODE_ANY = null;
private static final String EXTRA_VALUE_PAIR_SEPARATOR = ",";
private static final String EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable";
@@ -215,6 +216,12 @@
final InputMethodSubtype nonAutoJa = createDummyInputMethodSubtype("ja",
SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
!IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+ final InputMethodSubtype nonAutoHi = createDummyInputMethodSubtype("hi",
+ SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+ !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+ final InputMethodSubtype nonAutoHandwritingEn = createDummyInputMethodSubtype("en",
+ SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+ !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype =
createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
!IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
@@ -349,6 +356,57 @@
verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2, result.get(2));
}
+ // Make sure that if there is no subtype that matches the language requested, then we just
+ // use the first keyboard subtype.
+ {
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
+ subtypes.add(nonAutoHi);
+ subtypes.add(nonAutoEnUS);
+ subtypes.add(nonAutoHandwritingEn);
+ subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+ final InputMethodInfo imi = createDummyInputMethodInfo(
+ "com.android.apps.inputmethod.latin",
+ "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+ subtypes);
+ final ArrayList<InputMethodSubtype> result =
+ InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ getResourcesForLocales(LOCALE_JA_JP), imi);
+ assertEquals(1, result.size());
+ verifyEquality(nonAutoHi, result.get(0));
+ }
+ {
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
+ subtypes.add(nonAutoEnUS);
+ subtypes.add(nonAutoHi);
+ subtypes.add(nonAutoHandwritingEn);
+ subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+ final InputMethodInfo imi = createDummyInputMethodInfo(
+ "com.android.apps.inputmethod.latin",
+ "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+ subtypes);
+ final ArrayList<InputMethodSubtype> result =
+ InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ getResourcesForLocales(LOCALE_JA_JP), imi);
+ assertEquals(1, result.size());
+ verifyEquality(nonAutoEnUS, result.get(0));
+ }
+ {
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
+ subtypes.add(nonAutoHandwritingEn);
+ subtypes.add(nonAutoEnUS);
+ subtypes.add(nonAutoHi);
+ subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+ final InputMethodInfo imi = createDummyInputMethodInfo(
+ "com.android.apps.inputmethod.latin",
+ "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+ subtypes);
+ final ArrayList<InputMethodSubtype> result =
+ InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ getResourcesForLocales(LOCALE_JA_JP), imi);
+ assertEquals(1, result.size());
+ verifyEquality(nonAutoEnUS, result.get(0));
+ }
+
// Make sure that 3-letter language code can be handled.
{
final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 3901af3..ca214ab 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -40,6 +40,7 @@
import android.os.Build;
import android.util.ArrayMap;
import android.util.AttributeSet;
+import android.util.IntArray;
import android.util.Log;
import android.util.LongArray;
import android.util.PathParser;
@@ -629,12 +630,24 @@
*/
public void reset() {
ensureAnimatorSet();
+ if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+ Log.w(LOGTAG, "calling reset on AVD: " +
+ ((VectorDrawable.VectorDrawableState) ((AnimatedVectorDrawableState)
+ getConstantState()).mVectorDrawable.getConstantState()).mRootName
+ + ", at: " + this);
+ }
mAnimatorSet.reset();
}
@Override
public void start() {
ensureAnimatorSet();
+ if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+ Log.w(LOGTAG, "calling start on AVD: " +
+ ((VectorDrawable.VectorDrawableState) ((AnimatedVectorDrawableState)
+ getConstantState()).mVectorDrawable.getConstantState()).mRootName
+ + ", at: " + this);
+ }
mAnimatorSet.start();
}
@@ -652,6 +665,12 @@
@Override
public void stop() {
+ if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+ Log.w(LOGTAG, "calling stop on AVD: " +
+ ((VectorDrawable.VectorDrawableState) ((AnimatedVectorDrawableState)
+ getConstantState()).mVectorDrawable.getConstantState())
+ .mRootName + ", at: " + this);
+ }
mAnimatorSet.end();
}
@@ -864,9 +883,10 @@
* @hide
*/
public static class VectorDrawableAnimatorRT implements VectorDrawableAnimator {
- private static final int NONE = 0;
private static final int START_ANIMATION = 1;
private static final int REVERSE_ANIMATION = 2;
+ private static final int RESET_ANIMATION = 3;
+ private static final int END_ANIMATION = 4;
private AnimatorListener mListener = null;
private final LongArray mStartDelays = new LongArray();
private PropertyValuesHolder.PropertyValues mTmpValues =
@@ -882,7 +902,7 @@
private final VirtualRefBasePtr mSetRefBasePtr;
private WeakReference<RenderNode> mLastSeenTarget = null;
private int mLastListenerId = 0;
- private int mPendingAnimationAction = NONE;
+ private final IntArray mPendingAnimationActions = new IntArray();
private final Drawable mDrawable;
VectorDrawableAnimatorRT(AnimatedVectorDrawable drawable) {
@@ -1139,16 +1159,29 @@
protected void recordLastSeenTarget(DisplayListCanvas canvas) {
mLastSeenTarget = new WeakReference<RenderNode>(
RenderNodeAnimatorSetHelper.getTarget(canvas));
- if (mPendingAnimationAction != NONE) {
+ if (mPendingAnimationActions.size() > 0 && useLastSeenTarget()) {
if (DBG_ANIMATION_VECTOR_DRAWABLE) {
Log.d(LOGTAG, "Target is set in the next frame");
}
- if (mPendingAnimationAction == START_ANIMATION) {
- start();
- } else if (mPendingAnimationAction == REVERSE_ANIMATION) {
- reverse();
+ for (int i = 0; i < mPendingAnimationActions.size(); i++) {
+ handlePendingAction(mPendingAnimationActions.get(i));
}
- mPendingAnimationAction = NONE;
+ mPendingAnimationActions.clear();
+ }
+ }
+
+ private void handlePendingAction(int pendingAnimationAction) {
+ if (pendingAnimationAction == START_ANIMATION) {
+ startAnimation();
+ } else if (pendingAnimationAction == REVERSE_ANIMATION) {
+ reverseAnimation();
+ } else if (pendingAnimationAction == RESET_ANIMATION) {
+ resetAnimation();
+ } else if (pendingAnimationAction == END_ANIMATION) {
+ endAnimation();
+ } else {
+ throw new UnsupportedOperationException("Animation action " +
+ pendingAnimationAction + "is not supported");
}
}
@@ -1167,45 +1200,51 @@
mDrawable.invalidateSelf();
}
+ private void addPendingAction(int pendingAnimationAction) {
+ invalidateOwningView();
+ mPendingAnimationActions.add(pendingAnimationAction);
+ }
+
@Override
public void start() {
if (!mInitialized) {
return;
}
- if (!useLastSeenTarget()) {
- invalidateOwningView();
- mPendingAnimationAction = START_ANIMATION;
- return;
+ if (useLastSeenTarget()) {
+ if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+ Log.d(LOGTAG, "Target is set. Starting VDAnimatorSet from java");
+ }
+ startAnimation();
+ } else {
+ addPendingAction(START_ANIMATION);
}
- if (DBG_ANIMATION_VECTOR_DRAWABLE) {
- Log.d(LOGTAG, "Target is set. Starting VDAnimatorSet from java");
- }
-
- mStarted = true;
- nStart(mSetPtr, this, ++mLastListenerId);
- invalidateOwningView();
- if (mListener != null) {
- mListener.onAnimationStart(null);
- }
}
@Override
public void end() {
- if (mInitialized && useLastSeenTarget()) {
- // If no target has ever been set, no-op
- nEnd(mSetPtr);
- invalidateOwningView();
+ if (!mInitialized) {
+ return;
+ }
+
+ if (useLastSeenTarget()) {
+ endAnimation();
+ } else {
+ addPendingAction(END_ANIMATION);
}
}
@Override
public void reset() {
- if (mInitialized && useLastSeenTarget()) {
- // If no target has ever been set, no-op
- nReset(mSetPtr);
- invalidateOwningView();
+ if (!mInitialized) {
+ return;
+ }
+
+ if (useLastSeenTarget()) {
+ resetAnimation();
+ } else {
+ addPendingAction(RESET_ANIMATION);
}
}
@@ -1216,15 +1255,53 @@
if (!mIsReversible || !mInitialized) {
return;
}
- if (!useLastSeenTarget()) {
- invalidateOwningView();
- mPendingAnimationAction = REVERSE_ANIMATION;
- return;
+ if (useLastSeenTarget()) {
+ if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+ Log.d(LOGTAG, "Target is set. Reversing VDAnimatorSet from java");
+ }
+ reverseAnimation();
+ } else {
+ addPendingAction(REVERSE_ANIMATION);
}
+ }
+
+ // This should only be called after animator has been added to the RenderNode target.
+ private void startAnimation() {
if (DBG_ANIMATION_VECTOR_DRAWABLE) {
- Log.d(LOGTAG, "Target is set. Reversing VDAnimatorSet from java");
+ Log.w(LOGTAG, "starting animation on VD: " +
+ ((VectorDrawable.VectorDrawableState) ((AnimatedVectorDrawableState)
+ mDrawable.getConstantState()).mVectorDrawable.getConstantState())
+ .mRootName);
}
mStarted = true;
+ nStart(mSetPtr, this, ++mLastListenerId);
+ invalidateOwningView();
+ if (mListener != null) {
+ mListener.onAnimationStart(null);
+ }
+ }
+
+ // This should only be called after animator has been added to the RenderNode target.
+ private void endAnimation() {
+ if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+ Log.w(LOGTAG, "ending animation on VD: " +
+ ((VectorDrawable.VectorDrawableState) ((AnimatedVectorDrawableState)
+ mDrawable.getConstantState()).mVectorDrawable.getConstantState())
+ .mRootName);
+ }
+ nEnd(mSetPtr);
+ invalidateOwningView();
+ }
+
+ // This should only be called after animator has been added to the RenderNode target.
+ private void resetAnimation() {
+ nReset(mSetPtr);
+ invalidateOwningView();
+ }
+
+ // This should only be called after animator has been added to the RenderNode target.
+ private void reverseAnimation() {
+ mStarted = true;
nReverse(mSetPtr, this, ++mLastListenerId);
invalidateOwningView();
if (mListener != null) {
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 16bea79..f23fceb 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -1151,9 +1151,13 @@
uint32_t screenConfig2;
};
- // If true, it means that the script of the locale was explicitly provided.
- // If false, it means that the script was automatically computed.
- bool localeScriptWasProvided;
+ // If false and localeScript is set, it means that the script of the locale
+ // was explicitly provided.
+ //
+ // If true, it means that localeScript was automatically computed.
+ // localeScript may still not be set in this case, which means that we
+ // tried but could not compute a script.
+ bool localeScriptWasComputed;
void copyFromDeviceNoSwap(const ResTable_config& o);
@@ -1233,7 +1237,7 @@
inline void clearLocale() {
locale = 0;
- localeScriptWasProvided = false;
+ localeScriptWasComputed = false;
memset(localeScript, 0, sizeof(localeScript));
memset(localeVariant, 0, sizeof(localeVariant));
}
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 7adad8a..0886487 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -547,11 +547,8 @@
Intent intent = new Intent(IKeyChainService.class.getName());
ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
intent.setComponent(comp);
- boolean isBound = context.bindServiceAsUser(intent,
- keyChainServiceConnection,
- Context.BIND_AUTO_CREATE,
- user);
- if (!isBound) {
+ if (comp == null || !context.bindServiceAsUser(
+ intent, keyChainServiceConnection, Context.BIND_AUTO_CREATE, user)) {
throw new AssertionError("could not bind to KeyChainService");
}
return new KeyChainConnection(context, keyChainServiceConnection, q.take());
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index c73bb584..49b3a51 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -1870,8 +1870,8 @@
// The language & region are equal, so compare the scripts and variants.
const char emptyScript[sizeof(l.localeScript)] = {'\0', '\0', '\0', '\0'};
- const char *lScript = l.localeScriptWasProvided ? l.localeScript : emptyScript;
- const char *rScript = r.localeScriptWasProvided ? r.localeScript : emptyScript;
+ const char *lScript = l.localeScriptWasComputed ? emptyScript : l.localeScript;
+ const char *rScript = r.localeScriptWasComputed ? emptyScript : r.localeScript;
int script = memcmp(lScript, rScript, sizeof(l.localeScript));
if (script) {
return script;
@@ -2016,11 +2016,11 @@
// 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 = (localeScriptWasProvided ? 1 : 0) +
- ((localeVariant[0] != 0) ? 2 : 0);
+ const int score = ((localeScript[0] != '\0' && !localeScriptWasComputed) ? 1 : 0) +
+ ((localeVariant[0] != '\0') ? 2 : 0);
- const int oScore = (o.localeScriptWasProvided ? 1 : 0) +
- ((o.localeVariant[0] != 0) ? 2 : 0);
+ const int oScore = (o.localeScript[0] != '\0' && !o.localeScriptWasComputed ? 1 : 0) +
+ ((o.localeVariant[0] != '\0') ? 2 : 0);
return score - oScore;
@@ -2535,7 +2535,8 @@
if (settings.localeScript[0] == '\0') { // could not determine the request's script
countriesMustMatch = true;
} else {
- if (localeScript[0] == '\0') { // script was not provided, so we try to compute it
+ if (localeScript[0] == '\0' && !localeScriptWasComputed) {
+ // script was not provided or computed, so we try to compute it
localeDataComputeScript(computed_script, language, country);
if (computed_script[0] == '\0') { // we could not compute the script
countriesMustMatch = true;
@@ -2684,8 +2685,8 @@
if (!language[0]) {
return;
}
-
- if (!localeScriptWasProvided && !localeVariant[0]) {
+ const bool scriptWasProvided = localeScript[0] != '\0' && !localeScriptWasComputed;
+ if (!scriptWasProvided && !localeVariant[0]) {
// Legacy format.
if (out.size() > 0) {
out.append("-");
@@ -2715,7 +2716,7 @@
size_t len = unpackLanguage(buf);
out.append(buf, len);
- if (localeScriptWasProvided) {
+ if (scriptWasProvided) {
out.append("+");
out.append(localeScript, sizeof(localeScript));
}
@@ -2746,7 +2747,7 @@
charsWritten += unpackLanguage(str);
}
- if (localeScriptWasProvided) {
+ if (localeScript[0] && !localeScriptWasComputed) {
if (charsWritten) {
str[charsWritten++] = '-';
}
@@ -2787,7 +2788,6 @@
for (size_t i = 1; i < 4; ++i) {
config->localeScript[i] = tolower(start[i]);
}
- config->localeScriptWasProvided = true;
break;
}
case 5:
@@ -2807,7 +2807,6 @@
void ResTable_config::setBcp47Locale(const char* in) {
locale = 0;
- localeScriptWasProvided = false;
memset(localeScript, 0, sizeof(localeScript));
memset(localeVariant, 0, sizeof(localeVariant));
@@ -2824,9 +2823,10 @@
const size_t size = in + strlen(in) - start;
assignLocaleComponent(this, start, size);
- if (localeScript[0] == '\0') {
+ localeScriptWasComputed = (localeScript[0] == '\0');
+ if (localeScriptWasComputed) {
computeScript();
- };
+ }
}
String8 ResTable_config::toString() const {
diff --git a/libs/androidfw/tests/ConfigLocale_test.cpp b/libs/androidfw/tests/ConfigLocale_test.cpp
index 4b8d65c..2bf9b12 100644
--- a/libs/androidfw/tests/ConfigLocale_test.cpp
+++ b/libs/androidfw/tests/ConfigLocale_test.cpp
@@ -125,10 +125,10 @@
if (script != NULL) {
memcpy(out->localeScript, script, 4);
- out->localeScriptWasProvided = true;
+ out->localeScriptWasComputed = false;
} else {
out->computeScript();
- out->localeScriptWasProvided = false;
+ out->localeScriptWasComputed = true;
}
if (variant != NULL) {
@@ -182,7 +182,7 @@
EXPECT_EQ('n', test.language[1]);
EXPECT_EQ('U', test.country[0]);
EXPECT_EQ('S', test.country[1]);
- EXPECT_FALSE(test.localeScriptWasProvided);
+ EXPECT_TRUE(test.localeScriptWasComputed);
EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
EXPECT_EQ(0, test.localeVariant[0]);
@@ -203,7 +203,7 @@
EXPECT_EQ('e', test.language[0]);
EXPECT_EQ('n', test.language[1]);
EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
- EXPECT_TRUE(test.localeScriptWasProvided);
+ EXPECT_FALSE(test.localeScriptWasComputed);
memset(out, 1, 4);
test.unpackRegion(out);
EXPECT_EQ('4', out[0]);
@@ -216,7 +216,7 @@
EXPECT_EQ('d', out[0]);
EXPECT_EQ('e', out[1]);
EXPECT_EQ('\0', out[2]);
- EXPECT_FALSE(test.localeScriptWasProvided);
+ EXPECT_TRUE(test.localeScriptWasComputed);
EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
memset(out, 1, 4);
test.unpackRegion(out);
@@ -229,7 +229,7 @@
EXPECT_EQ('d', out[0]);
EXPECT_EQ('e', out[1]);
EXPECT_EQ('\0', out[2]);
- EXPECT_TRUE(test.localeScriptWasProvided);
+ EXPECT_FALSE(test.localeScriptWasComputed);
EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
memset(out, 1, 4);
test.unpackRegion(out);
@@ -270,11 +270,11 @@
fillIn("en", NULL, "Latn", NULL, &config);
char out[RESTABLE_MAX_LOCALE_LEN];
- config.localeScriptWasProvided = true;
+ config.localeScriptWasComputed = false;
config.getBcp47Locale(out);
EXPECT_EQ(0, strcmp("en-Latn", out));
- config.localeScriptWasProvided = false;
+ config.localeScriptWasComputed = true;
config.getBcp47Locale(out);
EXPECT_EQ(0, strcmp("en", out));
}
@@ -379,7 +379,7 @@
// emulate packages built with older AAPT
memset(supported.localeScript, '\0', 4);
- supported.localeScriptWasProvided = false;
+ supported.localeScriptWasComputed = false;
EXPECT_TRUE(supported.match(requested));
}
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 54b453d..70995ac 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -2,7 +2,7 @@
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-HWUI_NEW_OPS := false
+HWUI_NEW_OPS := true
# Enables fine-grained GLES error checking
# If set to true, every GLES call is wrapped & error checked
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 8018006..06b712e 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -61,7 +61,10 @@
for (size_t i = 0; i < opList.count; i++) {
const BakedOpState& state = *(opList.states[i]);
TextureVertex* rectVerts = &vertices[i * 4];
- Rect opBounds = state.computedState.clippedBounds;
+
+ // calculate unclipped bounds, since they'll determine texture coordinates
+ Rect opBounds = state.op->unmappedBounds;
+ state.computedState.transform.mapRect(opBounds);
if (CC_LIKELY(state.computedState.transform.isPureTranslate())) {
// pure translate, so snap (same behavior as onBitmapOp)
opBounds.snapToPixelBoundaries();
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index 501cbe5..afe9807 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -375,15 +375,13 @@
serialization->rect.set(mClipRegion.getBounds());
break;
}
+ // TODO: this is only done for draw time, should eventually avoid for record time
+ serialization->rect.snapToPixelBoundaries();
mLastSerialization = serialization;
}
return mLastSerialization;
}
-inline static const Rect& getRect(const ClipBase* scb) {
- return reinterpret_cast<const ClipRect*>(scb)->rect;
-}
-
inline static const RectangleList& getRectList(const ClipBase* scb) {
return reinterpret_cast<const ClipRectList*>(scb)->rectList;
}
@@ -425,9 +423,10 @@
&& recordedClip->mode == ClipMode::Rectangle
&& recordedClipTransform.rectToRect())) {
// common case - result is a single rectangle
- auto rectClip = allocator.create<ClipRect>(getRect(recordedClip));
+ auto rectClip = allocator.create<ClipRect>(recordedClip->rect);
recordedClipTransform.mapRect(rectClip->rect);
rectClip->rect.doIntersect(mClipRect);
+ rectClip->rect.snapToPixelBoundaries();
mLastResolutionResult = rectClip;
} else if (CC_UNLIKELY(mMode == ClipMode::Region
|| recordedClip->mode == ClipMode::Region
@@ -438,11 +437,11 @@
case ClipMode::Rectangle:
if (CC_LIKELY(recordedClipTransform.rectToRect())) {
// simple transform, skip creating SkPath
- Rect resultClip(getRect(recordedClip));
+ Rect resultClip(recordedClip->rect);
recordedClipTransform.mapRect(resultClip);
other.setRect(resultClip.toSkIRect());
} else {
- SkPath transformedRect = pathFromTransformedRectangle(getRect(recordedClip),
+ SkPath transformedRect = pathFromTransformedRectangle(recordedClip->rect,
recordedClipTransform);
other.setPath(transformedRect, createViewportRegion());
}
@@ -474,6 +473,7 @@
regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
break;
}
+ // Don't need to snap, since region's in int bounds
regionClip->rect.set(regionClip->region.getBounds());
mLastResolutionResult = regionClip;
} else {
@@ -484,7 +484,7 @@
}
if (recordedClip->mode == ClipMode::Rectangle) {
- rectList.intersectWith(getRect(recordedClip), recordedClipTransform);
+ rectList.intersectWith(recordedClip->rect, recordedClipTransform);
} else {
const RectangleList& other = getRectList(recordedClip);
for (int i = 0; i < other.getTransformedRectanglesCount(); i++) {
@@ -495,6 +495,7 @@
}
}
rectListClip->rect = rectList.calculateBounds();
+ rectListClip->rect.snapToPixelBoundaries();
mLastResolutionResult = rectListClip;
}
}
@@ -505,7 +506,7 @@
if (!clip) return; // nothing to do
if (CC_LIKELY(clip->mode == ClipMode::Rectangle)) {
- clipRectWithTransform(getRect(clip), &transform, SkRegion::kIntersect_Op);
+ clipRectWithTransform(clip->rect, &transform, SkRegion::kIntersect_Op);
} else if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
auto&& rectList = getRectList(clip);
for (int i = 0; i < rectList.getTransformedRectanglesCount(); i++) {
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 1bc37e2..5642170 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -517,10 +517,6 @@
BakedOpState* bakedState = tryBakeOpState(op);
if (!bakedState) return; // quick rejected
- currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
-
- // TODO: Fix this ( b/26569206 )
-/*
// Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
// Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
// MergingDrawBatch::canMergeWith()
@@ -535,7 +531,6 @@
} else {
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
}
-*/
}
void FrameBuilder::deferBitmapMeshOp(const BitmapMeshOp& op) {
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 9ae2212..ddf0528 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -24,6 +24,14 @@
namespace android {
namespace uirenderer {
+
+static Rect sUnreasonablyLargeBounds(-10000, -10000, 10000, 10000);
+
+static const Rect& getConservativeOpBounds(const ClipBase* clip) {
+ // if op is clipped, that rect can be used, but otherwise just use a conservatively large rect
+ return clip ? clip->rect : sUnreasonablyLargeBounds;
+}
+
RecordingCanvas::RecordingCanvas(size_t width, size_t height)
: mState(*this)
, mResourceCache(ResourceCache::getInstance()) {
@@ -242,10 +250,8 @@
void RecordingCanvas::drawPaint(const SkPaint& paint) {
const ClipBase* clip = getRecordedClip();
- // if there's no current clip, draw a big rect and hope we cover the eventual clip bounds
- Rect bounds = clip ? clip->rect : Rect(-10000, -10000, 10000, 10000);
addOp(alloc().create_trivial<RectOp>(
- bounds,
+ getConservativeOpBounds(clip),
Matrix4::identity(),
clip,
refPaint(&paint)));
@@ -534,10 +540,11 @@
float hOffset, float vOffset, const SkPaint& paint) {
if (!glyphs || glyphCount <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
glyphs = refBuffer<glyph_t>(glyphs, glyphCount);
+ auto clip = getRecordedClip();
addOp(alloc().create_trivial<TextOnPathOp>(
- mState.getLocalClipBounds(), // TODO: explicitly define bounds
+ getConservativeOpBounds(clip), // TODO: explicitly define bounds
*(mState.currentSnapshot()->transform),
- getRecordedClip(),
+ clip,
refPaint(&paint), glyphs, glyphCount, refPath(&path), hOffset, vOffset));
}
@@ -586,10 +593,11 @@
void RecordingCanvas::callDrawGLFunction(Functor* functor) {
mDisplayList->functors.push_back(functor);
+ auto clip = getRecordedClip();
addOp(alloc().create_trivial<FunctorOp>(
- mState.getLocalClipBounds(), // TODO: explicitly define bounds
+ getConservativeOpBounds(clip), // TODO: explicitly define bounds
*(mState.currentSnapshot()->transform),
- getRecordedClip(),
+ clip,
functor));
}
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
index dc2ea07..822d04f 100644
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ b/libs/hwui/tests/unit/ClipAreaTests.cpp
@@ -27,7 +27,7 @@
namespace android {
namespace uirenderer {
-static Rect kViewportBounds(0, 0, 2048, 2048);
+static Rect kViewportBounds(2048, 2048);
static ClipArea createClipArea() {
ClipArea area;
@@ -140,17 +140,15 @@
// rect list
Matrix4 rotate;
- rotate.loadRotate(2.0f);
- area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op);
+ rotate.loadRotate(5.0f);
+ area.clipRectWithTransform(Rect(50, 50, 150, 150), &rotate, SkRegion::kIntersect_Op);
{
auto serializedClip = area.serializeClip(allocator);
ASSERT_NE(nullptr, serializedClip);
ASSERT_EQ(ClipMode::RectangleList, serializedClip->mode);
auto clipRectList = reinterpret_cast<const ClipRectList*>(serializedClip);
EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
- EXPECT_FALSE(clipRectList->rect.isEmpty());
- EXPECT_FLOAT_EQ(199.87817f, clipRectList->rect.right)
- << "Right side should be clipped by rotated rect";
+ EXPECT_EQ(Rect(37, 54, 145, 163), clipRectList->rect);
EXPECT_EQ(serializedClip, area.serializeClip(allocator))
<< "Requery of clip on unmodified ClipArea must return same pointer.";
}
@@ -241,5 +239,28 @@
}
}
+TEST(ClipArea, serializeIntersectedClip_snap) {
+ ClipArea area(createClipArea());
+ area.setClip(100.2, 100.4, 500.6, 500.8);
+ LinearAllocator allocator;
+
+ {
+ // no recorded clip case
+ auto resolvedClip = area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity());
+ EXPECT_EQ(Rect(100, 100, 501, 501), resolvedClip->rect);
+ }
+ {
+ // recorded clip case
+ ClipRect recordedClip(Rect(100.12, 100.74));
+ Matrix4 translateScale;
+ translateScale.loadTranslate(100, 100, 0);
+ translateScale.scale(2, 3, 1); // recorded clip will have non-int coords, even after transform
+ auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale);
+ ASSERT_NE(nullptr, resolvedClip);
+ EXPECT_EQ(ClipMode::Rectangle, resolvedClip->mode);
+ EXPECT_EQ(Rect(100, 100, 300, 402), resolvedClip->rect);
+ }
+}
+
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 8802d07..4c56a22 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -216,8 +216,7 @@
<< "Expect number of ops = 2 * loop count";
}
-// TODO: Disabled due to b/26793764
-TEST(FrameBuilder, DISABLED_clippedMerging) {
+TEST(FrameBuilder, clippedMerging) {
class ClippedMergingTestRenderer : public TestRendererBase {
public:
void onMergedBitmapOps(const MergedBakedOpList& opList) override {
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index c39047c..d35b1f9 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -442,9 +442,7 @@
// since the same clip will be computed at draw time. If such a change is made, this
// check could be done at record time by querying the clip, or the clip could be altered
// slightly so that it is serialized.
- EXPECT_RECT_APPROX_EQ(Rect(58.57864, 58.57864, 341.42136, 341.42136),
- (reinterpret_cast<const ClipRect*>(op.localClip))->rect);
-
+ EXPECT_EQ(Rect(59, 59, 341, 341), op.localClip->rect);
EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
expectedMatrix.loadIdentity();
EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
diff --git a/location/java/android/location/GnssClock.java b/location/java/android/location/GnssClock.java
index 3c8a78d..6a7801e 100644
--- a/location/java/android/location/GnssClock.java
+++ b/location/java/android/location/GnssClock.java
@@ -26,26 +26,26 @@
public final class GnssClock implements Parcelable {
// The following enumerations must be in sync with the values declared in gps.h
- private static final short HAS_NO_FLAGS = 0;
- private static final short HAS_LEAP_SECOND = (1<<0);
- private static final short HAS_TIME_UNCERTAINTY = (1<<1);
- private static final short HAS_FULL_BIAS = (1<<2);
- private static final short HAS_BIAS = (1<<3);
- private static final short HAS_BIAS_UNCERTAINTY = (1<<4);
- private static final short HAS_DRIFT = (1<<5);
- private static final short HAS_DRIFT_UNCERTAINTY = (1<<6);
+ private static final int HAS_NO_FLAGS = 0;
+ private static final int HAS_LEAP_SECOND = (1<<0);
+ private static final int HAS_TIME_UNCERTAINTY = (1<<1);
+ private static final int HAS_FULL_BIAS = (1<<2);
+ private static final int HAS_BIAS = (1<<3);
+ private static final int HAS_BIAS_UNCERTAINTY = (1<<4);
+ private static final int HAS_DRIFT = (1<<5);
+ private static final int HAS_DRIFT_UNCERTAINTY = (1<<6);
// End enumerations in sync with gps.h
- private short mFlags;
- private short mLeapSecond;
- private long mTimeInNs;
- private double mTimeUncertaintyInNs;
- private long mFullBiasInNs;
- private double mBiasInNs;
- private double mBiasUncertaintyInNs;
- private double mDriftInNsPerSec;
- private double mDriftUncertaintyInNsPerSec;
+ private int mFlags;
+ private int mLeapSecond;
+ private long mTimeNanos;
+ private double mTimeUncertaintyNanos;
+ private long mFullBiasNanos;
+ private double mBiasNanos;
+ private double mBiasUncertaintyNanos;
+ private double mDriftNanosPerSecond;
+ private double mDriftUncertaintyNanosPerSecond;
private int mHardwareClockDiscontinuityCount;
GnssClock() {
@@ -58,13 +58,13 @@
public void set(GnssClock clock) {
mFlags = clock.mFlags;
mLeapSecond = clock.mLeapSecond;
- mTimeInNs = clock.mTimeInNs;
- mTimeUncertaintyInNs = clock.mTimeUncertaintyInNs;
- mFullBiasInNs = clock.mFullBiasInNs;
- mBiasInNs = clock.mBiasInNs;
- mBiasUncertaintyInNs = clock.mBiasUncertaintyInNs;
- mDriftInNsPerSec = clock.mDriftInNsPerSec;
- mDriftUncertaintyInNsPerSec = clock.mDriftUncertaintyInNsPerSec;
+ mTimeNanos = clock.mTimeNanos;
+ mTimeUncertaintyNanos = clock.mTimeUncertaintyNanos;
+ mFullBiasNanos = clock.mFullBiasNanos;
+ mBiasNanos = clock.mBiasNanos;
+ mBiasUncertaintyNanos = clock.mBiasUncertaintyNanos;
+ mDriftNanosPerSecond = clock.mDriftNanosPerSecond;
+ mDriftUncertaintyNanosPerSecond = clock.mDriftUncertaintyNanosPerSecond;
mHardwareClockDiscontinuityCount = clock.mHardwareClockDiscontinuityCount;
}
@@ -89,14 +89,14 @@
*
* The value is only available if {@link #hasLeapSecond()} is true.
*/
- public short getLeapSecond() {
+ public int getLeapSecond() {
return mLeapSecond;
}
/**
* Sets the leap second associated with the clock's time.
*/
- public void setLeapSecond(short leapSecond) {
+ public void setLeapSecond(int leapSecond) {
setFlag(HAS_LEAP_SECOND);
mLeapSecond = leapSecond;
}
@@ -106,7 +106,7 @@
*/
public void resetLeapSecond() {
resetFlag(HAS_LEAP_SECOND);
- mLeapSecond = Short.MIN_VALUE;
+ mLeapSecond = Integer.MIN_VALUE;
}
/**
@@ -114,30 +114,30 @@
*
* For 'local hardware clock' this value is expected to be monotonically increasing during the
* reporting session. The real GPS time can be derived by compensating
- * {@link #getFullBiasInNs()} (when it is available) from this value.
+ * {@link #getFullBiasNanos()} (when it is available) from this value.
*
* For 'GPS time' this value is expected to be the best estimation of current GPS time that GPS
- * receiver can achieve. {@link #getTimeUncertaintyInNs()} should be available when GPS time is
+ * receiver can achieve. {@link #getTimeUncertaintyNanos()} should be available when GPS time is
* specified.
*
- * Sub-nanosecond accuracy can be provided by means of {@link #getBiasInNs()}.
- * The reported time includes {@link #getTimeUncertaintyInNs()}.
+ * Sub-nanosecond accuracy can be provided by means of {@link #getBiasNanos()}.
+ * The reported time includes {@link #getTimeUncertaintyNanos()}.
*/
- public long getTimeInNs() {
- return mTimeInNs;
+ public long getTimeNanos() {
+ return mTimeNanos;
}
/**
- * Sets the GPS receiver internal clock in nanoseconds.
+ * Sets the GNSS receiver internal clock in nanoseconds.
*/
- public void setTimeInNs(long timeInNs) {
- mTimeInNs = timeInNs;
+ public void setTimeNanos(long timeNanos) {
+ mTimeNanos = timeNanos;
}
/**
- * Returns true if {@link #getTimeUncertaintyInNs()} is available, false otherwise.
+ * Returns true if {@link #getTimeUncertaintyNanos()} is available, false otherwise.
*/
- public boolean hasTimeUncertaintyInNs() {
+ public boolean hasTimeUncertaintyNanos() {
return isFlagSet(HAS_TIME_UNCERTAINTY);
}
@@ -145,189 +145,189 @@
* Gets the clock's time Uncertainty (1-Sigma) in nanoseconds.
* The uncertainty is represented as an absolute (single sided) value.
*
- * The value is only available if {@link #hasTimeUncertaintyInNs()} is true.
+ * The value is only available if {@link #hasTimeUncertaintyNanos()} is true.
*/
- public double getTimeUncertaintyInNs() {
- return mTimeUncertaintyInNs;
+ public double getTimeUncertaintyNanos() {
+ return mTimeUncertaintyNanos;
}
/**
* Sets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
*/
- public void setTimeUncertaintyInNs(double timeUncertaintyInNs) {
+ public void setTimeUncertaintyNanos(double timeUncertaintyNanos) {
setFlag(HAS_TIME_UNCERTAINTY);
- mTimeUncertaintyInNs = timeUncertaintyInNs;
+ mTimeUncertaintyNanos = timeUncertaintyNanos;
}
/**
* Resets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
*/
- public void resetTimeUncertaintyInNs() {
+ public void resetTimeUncertaintyNanos() {
resetFlag(HAS_TIME_UNCERTAINTY);
- mTimeUncertaintyInNs = Double.NaN;
+ mTimeUncertaintyNanos = Double.NaN;
}
/**
- * Returns true if {@link #getFullBiasInNs()} is available, false otherwise.
+ * Returns true if {@link #getFullBiasNanos()} is available, false otherwise.
*/
- public boolean hasFullBiasInNs() {
+ public boolean hasFullBiasNanos() {
return isFlagSet(HAS_FULL_BIAS);
}
/**
- * Gets the difference between hardware clock ({@link #getTimeInNs()}) inside GPS receiver and
+ * Gets the difference between hardware clock ({@link #getTimeNanos()}) inside GPS receiver and
* the true GPS time since 0000Z, January 6, 1980, in nanoseconds.
*
* This value is available if the receiver has estimated GPS time. If the computed time is for a
* non-GPS constellation, the time offset of that constellation to GPS has to be applied to fill
- * this value. The value contains the 'bias uncertainty' {@link #getBiasUncertaintyInNs()} in
+ * this value. The value contains the 'bias uncertainty' {@link #getBiasUncertaintyNanos()} in
* it, and it should be used for quality check. The value is only available if
- * {@link #hasFullBiasInNs()} is true.
+ * {@link #hasFullBiasNanos()} is true.
*
* The sign of the value is defined by the following equation:
* local estimate of GPS time = time_ns + (full_bias_ns + bias_ns)
*/
- public long getFullBiasInNs() {
- return mFullBiasInNs;
+ public long getFullBiasNanos() {
+ return mFullBiasNanos;
}
/**
* Sets the full bias in nanoseconds.
*/
- public void setFullBiasInNs(long value) {
+ public void setFullBiasNanos(long value) {
setFlag(HAS_FULL_BIAS);
- mFullBiasInNs = value;
+ mFullBiasNanos = value;
}
/**
* Resets the full bias in nanoseconds.
*/
- public void resetFullBiasInNs() {
+ public void resetFullBiasNanos() {
resetFlag(HAS_FULL_BIAS);
- mFullBiasInNs = Long.MIN_VALUE;
+ mFullBiasNanos = Long.MIN_VALUE;
}
/**
- * Returns true if {@link #getBiasInNs()} is available, false otherwise.
+ * Returns true if {@link #getBiasNanos()} is available, false otherwise.
*/
- public boolean hasBiasInNs() {
+ public boolean hasBiasNanos() {
return isFlagSet(HAS_BIAS);
}
/**
* Gets the clock's sub-nanosecond bias.
- * The reported bias includes {@link #getBiasUncertaintyInNs()}.
+ * The reported bias includes {@link #getBiasUncertaintyNanos()}.
*
- * The value is only available if {@link #hasBiasInNs()} is true.
+ * The value is only available if {@link #hasBiasNanos()} is true.
*/
- public double getBiasInNs() {
- return mBiasInNs;
+ public double getBiasNanos() {
+ return mBiasNanos;
}
/**
* Sets the sub-nanosecond bias.
*/
- public void setBiasInNs(double biasInNs) {
+ public void setBiasNanos(double biasNanos) {
setFlag(HAS_BIAS);
- mBiasInNs = biasInNs;
+ mBiasNanos = biasNanos;
}
/**
* Resets the clock's Bias in nanoseconds.
*/
- public void resetBiasInNs() {
+ public void resetBiasNanos() {
resetFlag(HAS_BIAS);
- mBiasInNs = Double.NaN;
+ mBiasNanos = Double.NaN;
}
/**
- * Returns true if {@link #getBiasUncertaintyInNs()} is available, false otherwise.
+ * Returns true if {@link #getBiasUncertaintyNanos()} is available, false otherwise.
*/
- public boolean hasBiasUncertaintyInNs() {
+ public boolean hasBiasUncertaintyNanos() {
return isFlagSet(HAS_BIAS_UNCERTAINTY);
}
/**
* Gets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
*
- * The value is only available if {@link #hasBiasUncertaintyInNs()} is true.
+ * The value is only available if {@link #hasBiasUncertaintyNanos()} is true.
*/
- public double getBiasUncertaintyInNs() {
- return mBiasUncertaintyInNs;
+ public double getBiasUncertaintyNanos() {
+ return mBiasUncertaintyNanos;
}
/**
* Sets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
*/
- public void setBiasUncertaintyInNs(double biasUncertaintyInNs) {
+ public void setBiasUncertaintyNanos(double biasUncertaintyNanos) {
setFlag(HAS_BIAS_UNCERTAINTY);
- mBiasUncertaintyInNs = biasUncertaintyInNs;
+ mBiasUncertaintyNanos = biasUncertaintyNanos;
}
/**
* Resets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
*/
- public void resetBiasUncertaintyInNs() {
+ public void resetBiasUncertaintyNanos() {
resetFlag(HAS_BIAS_UNCERTAINTY);
- mBiasUncertaintyInNs = Double.NaN;
+ mBiasUncertaintyNanos = Double.NaN;
}
/**
- * Returns true if {@link #getDriftInNsPerSec()} is available, false otherwise.
+ * Returns true if {@link #getDriftNanosPerSecond()} is available, false otherwise.
*/
- public boolean hasDriftInNsPerSec() {
+ public boolean hasDriftNanosPerSecond() {
return isFlagSet(HAS_DRIFT);
}
/**
* Gets the clock's Drift in nanoseconds per second.
* A positive value indicates that the frequency is higher than the nominal frequency.
- * The reported drift includes {@link #getDriftUncertaintyInNsPerSec()}.
+ * The reported drift includes {@link #getDriftUncertaintyNanosPerSecond()}.
*
- * The value is only available if {@link #hasDriftInNsPerSec()} is true.
+ * The value is only available if {@link #hasDriftNanosPerSecond()} is true.
*/
- public double getDriftInNsPerSec() {
- return mDriftInNsPerSec;
+ public double getDriftNanosPerSecond() {
+ return mDriftNanosPerSecond;
}
/**
* Sets the clock's Drift in nanoseconds per second.
*/
- public void setDriftInNsPerSec(double driftInNsPerSec) {
+ public void setDriftNanosPerSecond(double driftNanosPerSecond) {
setFlag(HAS_DRIFT);
- mDriftInNsPerSec = driftInNsPerSec;
+ mDriftNanosPerSecond = driftNanosPerSecond;
}
/**
* Resets the clock's Drift in nanoseconds per second.
*/
- public void resetDriftInNsPerSec() {
+ public void resetDriftNanosPerSecond() {
resetFlag(HAS_DRIFT);
- mDriftInNsPerSec = Double.NaN;
+ mDriftNanosPerSecond = Double.NaN;
}
/**
- * Returns true if {@link #getDriftUncertaintyInNsPerSec()} is available, false otherwise.
+ * Returns true if {@link #getDriftUncertaintyNanosPerSecond()} is available, false otherwise.
*/
- public boolean hasDriftUncertaintyInNsPerSec() {
+ public boolean hasDriftUncertaintyNanosPerSecond() {
return isFlagSet(HAS_DRIFT_UNCERTAINTY);
}
/**
* Gets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
*
- * The value is only available if {@link #hasDriftUncertaintyInNsPerSec()} is true.
+ * The value is only available if {@link #hasDriftUncertaintyNanosPerSecond()} is true.
*/
- public double getDriftUncertaintyInNsPerSec() {
- return mDriftUncertaintyInNsPerSec;
+ public double getDriftUncertaintyNanosPerSecond() {
+ return mDriftUncertaintyNanosPerSecond;
}
/**
* Sets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
*/
- public void setDriftUncertaintyInNsPerSec(double driftUncertaintyInNsPerSec) {
+ public void setDriftUncertaintyNanosPerSecond(double driftUncertaintyNanosPerSecond) {
setFlag(HAS_DRIFT_UNCERTAINTY);
- mDriftUncertaintyInNsPerSec = driftUncertaintyInNsPerSec;
+ mDriftUncertaintyNanosPerSecond = driftUncertaintyNanosPerSecond;
}
/**
@@ -347,9 +347,9 @@
/**
* Resets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
*/
- public void resetDriftUncertaintyInNsPerSec() {
+ public void resetDriftUncertaintyNanosPerSecond() {
resetFlag(HAS_DRIFT_UNCERTAINTY);
- mDriftUncertaintyInNsPerSec = Double.NaN;
+ mDriftUncertaintyNanosPerSecond = Double.NaN;
}
public static final Creator<GnssClock> CREATOR = new Creator<GnssClock>() {
@@ -357,15 +357,15 @@
public GnssClock createFromParcel(Parcel parcel) {
GnssClock gpsClock = new GnssClock();
- gpsClock.mFlags = (short) parcel.readInt();
- gpsClock.mLeapSecond = (short) parcel.readInt();
- gpsClock.mTimeInNs = parcel.readLong();
- gpsClock.mTimeUncertaintyInNs = parcel.readDouble();
- gpsClock.mFullBiasInNs = parcel.readLong();
- gpsClock.mBiasInNs = parcel.readDouble();
- gpsClock.mBiasUncertaintyInNs = parcel.readDouble();
- gpsClock.mDriftInNsPerSec = parcel.readDouble();
- gpsClock.mDriftUncertaintyInNsPerSec = parcel.readDouble();
+ gpsClock.mFlags = parcel.readInt();
+ gpsClock.mLeapSecond = parcel.readInt();
+ gpsClock.mTimeNanos = parcel.readLong();
+ gpsClock.mTimeUncertaintyNanos = parcel.readDouble();
+ gpsClock.mFullBiasNanos = parcel.readLong();
+ gpsClock.mBiasNanos = parcel.readDouble();
+ gpsClock.mBiasUncertaintyNanos = parcel.readDouble();
+ gpsClock.mDriftNanosPerSecond = parcel.readDouble();
+ gpsClock.mDriftUncertaintyNanosPerSecond = parcel.readDouble();
gpsClock.mHardwareClockDiscontinuityCount = parcel.readInt();
return gpsClock;
@@ -381,13 +381,13 @@
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mFlags);
parcel.writeInt(mLeapSecond);
- parcel.writeLong(mTimeInNs);
- parcel.writeDouble(mTimeUncertaintyInNs);
- parcel.writeLong(mFullBiasInNs);
- parcel.writeDouble(mBiasInNs);
- parcel.writeDouble(mBiasUncertaintyInNs);
- parcel.writeDouble(mDriftInNsPerSec);
- parcel.writeDouble(mDriftUncertaintyInNsPerSec);
+ parcel.writeLong(mTimeNanos);
+ parcel.writeDouble(mTimeUncertaintyNanos);
+ parcel.writeLong(mFullBiasNanos);
+ parcel.writeDouble(mBiasNanos);
+ parcel.writeDouble(mBiasUncertaintyNanos);
+ parcel.writeDouble(mDriftNanosPerSecond);
+ parcel.writeDouble(mDriftUncertaintyNanosPerSecond);
parcel.writeInt(mHardwareClockDiscontinuityCount);
}
@@ -406,29 +406,29 @@
builder.append(String.format(
formatWithUncertainty,
- "TimeInNs",
- mTimeInNs,
- "TimeUncertaintyInNs",
- hasTimeUncertaintyInNs() ? mTimeUncertaintyInNs : null));
+ "TimeNanos",
+ mTimeNanos,
+ "TimeUncertaintyNanos",
+ hasTimeUncertaintyNanos() ? mTimeUncertaintyNanos : null));
builder.append(String.format(
format,
- "FullBiasInNs",
- hasFullBiasInNs() ? mFullBiasInNs : null));
+ "FullBiasNanos",
+ hasFullBiasNanos() ? mFullBiasNanos : null));
builder.append(String.format(
formatWithUncertainty,
- "BiasInNs",
- hasBiasInNs() ? mBiasInNs : null,
- "BiasUncertaintyInNs",
- hasBiasUncertaintyInNs() ? mBiasUncertaintyInNs : null));
+ "BiasNanos",
+ hasBiasNanos() ? mBiasNanos : null,
+ "BiasUncertaintyNanos",
+ hasBiasUncertaintyNanos() ? mBiasUncertaintyNanos : null));
builder.append(String.format(
formatWithUncertainty,
- "DriftInNsPerSec",
- hasDriftInNsPerSec() ? mDriftInNsPerSec : null,
- "DriftUncertaintyInNsPerSec",
- hasDriftUncertaintyInNsPerSec() ? mDriftUncertaintyInNsPerSec : null));
+ "DriftNanosPerSecond",
+ hasDriftNanosPerSecond() ? mDriftNanosPerSecond : null,
+ "DriftUncertaintyNanosPerSecond",
+ hasDriftUncertaintyNanosPerSecond() ? mDriftUncertaintyNanosPerSecond : null));
return builder.toString();
}
@@ -436,25 +436,25 @@
private void initialize() {
mFlags = HAS_NO_FLAGS;
resetLeapSecond();
- setTimeInNs(Long.MIN_VALUE);
- resetTimeUncertaintyInNs();
- resetFullBiasInNs();
- resetBiasInNs();
- resetBiasUncertaintyInNs();
- resetDriftInNsPerSec();
- resetDriftUncertaintyInNsPerSec();
+ setTimeNanos(Long.MIN_VALUE);
+ resetTimeUncertaintyNanos();
+ resetFullBiasNanos();
+ resetBiasNanos();
+ resetBiasUncertaintyNanos();
+ resetDriftNanosPerSecond();
+ resetDriftUncertaintyNanosPerSecond();
setHardwareClockDiscontinuityCount(Integer.MIN_VALUE);
}
- private void setFlag(short flag) {
+ private void setFlag(int flag) {
mFlags |= flag;
}
- private void resetFlag(short flag) {
+ private void resetFlag(int flag) {
mFlags &= ~flag;
}
- private boolean isFlagSet(short flag) {
+ private boolean isFlagSet(int flag) {
return (mFlags & flag) == flag;
}
}
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index abdc13c..367c52f 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -28,82 +28,35 @@
*/
public final class GnssMeasurement implements Parcelable {
private int mFlags;
- private short mSvid;
- private byte mConstellationType;
- private double mTimeOffsetInNs;
- private short mState;
- private long mReceivedSvTimeInNs;
- private long mReceivedSvTimeUncertaintyInNs;
- private double mCn0InDbHz;
- private double mPseudorangeRateInMetersPerSec;
- private double mPseudorangeRateUncertaintyInMetersPerSec;
- private short mAccumulatedDeltaRangeState;
- private double mAccumulatedDeltaRangeInMeters;
- private double mAccumulatedDeltaRangeUncertaintyInMeters;
- private double mPseudorangeInMeters;
- private double mPseudorangeUncertaintyInMeters;
- private double mCodePhaseInChips;
- private double mCodePhaseUncertaintyInChips;
- private float mCarrierFrequencyInHz;
+ private int mSvid;
+ private int mConstellationType;
+ private double mTimeOffsetNanos;
+ private int mState;
+ private long mReceivedSvTimeNanos;
+ private long mReceivedSvTimeUncertaintyNanos;
+ private double mCn0DbHz;
+ private double mPseudorangeRateMetersPerSecond;
+ private double mPseudorangeRateUncertaintyMetersPerSecond;
+ private int mAccumulatedDeltaRangeState;
+ private double mAccumulatedDeltaRangeMeters;
+ private double mAccumulatedDeltaRangeUncertaintyMeters;
+ private float mCarrierFrequencyHz;
private long mCarrierCycles;
private double mCarrierPhase;
private double mCarrierPhaseUncertainty;
- private byte mLossOfLock;
- private int mBitNumber;
- private short mTimeFromLastBitInMs;
- private double mDopplerShiftInHz;
- private double mDopplerShiftUncertaintyInHz;
- private byte mMultipathIndicator;
+ private int mMultipathIndicator;
private double mSnrInDb;
- private double mElevationInDeg;
- private double mElevationUncertaintyInDeg;
- private double mAzimuthInDeg;
- private double mAzimuthUncertaintyInDeg;
- private boolean mUsedInFix;
// The following enumerations must be in sync with the values declared in gps.h
private static final int HAS_NO_FLAGS = 0;
private static final int HAS_SNR = (1<<0);
- private static final int HAS_ELEVATION = (1<<1);
- private static final int HAS_ELEVATION_UNCERTAINTY = (1<<2);
- private static final int HAS_AZIMUTH = (1<<3);
- private static final int HAS_AZIMUTH_UNCERTAINTY = (1<<4);
- private static final int HAS_PSEUDORANGE = (1<<5);
- private static final int HAS_PSEUDORANGE_UNCERTAINTY = (1<<6);
- private static final int HAS_CODE_PHASE = (1<<7);
- private static final int HAS_CODE_PHASE_UNCERTAINTY = (1<<8);
private static final int HAS_CARRIER_FREQUENCY = (1<<9);
private static final int HAS_CARRIER_CYCLES = (1<<10);
private static final int HAS_CARRIER_PHASE = (1<<11);
private static final int HAS_CARRIER_PHASE_UNCERTAINTY = (1<<12);
- private static final int HAS_BIT_NUMBER = (1<<13);
- private static final int HAS_TIME_FROM_LAST_BIT = (1<<14);
- private static final int HAS_DOPPLER_SHIFT = (1<<15);
- private static final int HAS_DOPPLER_SHIFT_UNCERTAINTY = (1<<16);
- // private static final int HAS_USED_IN_FIX = (1<<17);
private static final int HAS_UNCORRECTED_PSEUDORANGE_RATE = (1<<18);
- /** The status of 'loss of lock'. */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({LOSS_OF_LOCK_UNKNOWN, LOSS_OF_LOCK_OK, LOSS_OF_LOCK_CYCLE_SLIP})
- public @interface LossOfLockStatus {}
-
- /**
- * The indicator is not available or it is unknown.
- */
- public static final byte LOSS_OF_LOCK_UNKNOWN = 0;
-
- /**
- * The measurement does not present any indication of 'loss of lock'.
- */
- public static final byte LOSS_OF_LOCK_OK = 1;
-
- /**
- * 'Loss of lock' detected between the previous and current observation: cycle slip possible.
- */
- public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2;
-
/** The status of multipath. */
@Retention(RetentionPolicy.SOURCE)
@IntDef({MULTIPATH_INDICATOR_UNKNOWN, MULTIPATH_INDICATOR_DETECTED,
@@ -113,78 +66,78 @@
/**
* The indicator is not available or it is unknown.
*/
- public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0;
+ public static final int MULTIPATH_INDICATOR_UNKNOWN = 0;
/**
* The measurement has been indicated to use multi-path.
*/
- public static final byte MULTIPATH_INDICATOR_DETECTED = 1;
+ public static final int MULTIPATH_INDICATOR_DETECTED = 1;
/**
* The measurement has been indicated not tu use multi-path.
*/
- public static final byte MULTIPATH_INDICATOR_NOT_USED = 2;
+ public static final int MULTIPATH_INDICATOR_NOT_USED = 2;
/**
* The state of GNSS receiver the measurement is invalid or unknown.
*/
- public static final short STATE_UNKNOWN = 0;
+ public static final int STATE_UNKNOWN = 0;
/**
* The state of the GNSS receiver is ranging code lock.
*/
- public static final short STATE_CODE_LOCK = (1<<0);
+ public static final int STATE_CODE_LOCK = (1<<0);
/**
* The state of the GNSS receiver is in bit sync.
*/
- public static final short STATE_BIT_SYNC = (1<<1);
+ public static final int STATE_BIT_SYNC = (1<<1);
/**
*The state of the GNSS receiver is in sub-frame sync.
*/
- public static final short STATE_SUBFRAME_SYNC = (1<<2);
+ public static final int STATE_SUBFRAME_SYNC = (1<<2);
/**
* The state of the GNSS receiver has TOW decoded.
*/
- public static final short STATE_TOW_DECODED = (1<<3);
+ public static final int STATE_TOW_DECODED = (1<<3);
/**
* The state of the GNSS receiver contains millisecond ambiguity.
*/
- public static final short STATE_MSEC_AMBIGUOUS = (1<<4);
+ public static final int STATE_MSEC_AMBIGUOUS = (1<<4);
/**
* All the GNSS receiver state flags.
*/
- private static final short STATE_ALL = STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_SUBFRAME_SYNC
+ private static final int STATE_ALL = STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_SUBFRAME_SYNC
| STATE_TOW_DECODED | STATE_MSEC_AMBIGUOUS;
/**
* The state of the 'Accumulated Delta Range' is invalid or unknown.
*/
- public static final short ADR_STATE_UNKNOWN = 0;
+ public static final int ADR_STATE_UNKNOWN = 0;
/**
* The state of the 'Accumulated Delta Range' is valid.
*/
- public static final short ADR_STATE_VALID = (1<<0);
+ public static final int ADR_STATE_VALID = (1<<0);
/**
* The state of the 'Accumulated Delta Range' has detected a reset.
*/
- public static final short ADR_STATE_RESET = (1<<1);
+ public static final int ADR_STATE_RESET = (1<<1);
/**
* The state of the 'Accumulated Delta Range' has a cycle slip detected.
*/
- public static final short ADR_STATE_CYCLE_SLIP = (1<<2);
+ public static final int ADR_STATE_CYCLE_SLIP = (1<<2);
/**
* All the 'Accumulated Delta Range' flags.
*/
- private static final short ADR_ALL = ADR_STATE_VALID | ADR_STATE_RESET | ADR_STATE_CYCLE_SLIP;
+ private static final int ADR_ALL = ADR_STATE_VALID | ADR_STATE_RESET | ADR_STATE_CYCLE_SLIP;
// End enumerations in sync with gps.h
@@ -199,38 +152,24 @@
mFlags = measurement.mFlags;
mSvid = measurement.mSvid;
mConstellationType = measurement.mConstellationType;
- mTimeOffsetInNs = measurement.mTimeOffsetInNs;
+ mTimeOffsetNanos = measurement.mTimeOffsetNanos;
mState = measurement.mState;
- mReceivedSvTimeInNs = measurement.mReceivedSvTimeInNs;
- mReceivedSvTimeUncertaintyInNs = measurement.mReceivedSvTimeUncertaintyInNs;
- mCn0InDbHz = measurement.mCn0InDbHz;
- mPseudorangeRateInMetersPerSec = measurement.mPseudorangeRateInMetersPerSec;
- mPseudorangeRateUncertaintyInMetersPerSec =
- measurement.mPseudorangeRateUncertaintyInMetersPerSec;
+ mReceivedSvTimeNanos = measurement.mReceivedSvTimeNanos;
+ mReceivedSvTimeUncertaintyNanos = measurement.mReceivedSvTimeUncertaintyNanos;
+ mCn0DbHz = measurement.mCn0DbHz;
+ mPseudorangeRateMetersPerSecond = measurement.mPseudorangeRateMetersPerSecond;
+ mPseudorangeRateUncertaintyMetersPerSecond =
+ measurement.mPseudorangeRateUncertaintyMetersPerSecond;
mAccumulatedDeltaRangeState = measurement.mAccumulatedDeltaRangeState;
- mAccumulatedDeltaRangeInMeters = measurement.mAccumulatedDeltaRangeInMeters;
- mAccumulatedDeltaRangeUncertaintyInMeters =
- measurement.mAccumulatedDeltaRangeUncertaintyInMeters;
- mPseudorangeInMeters = measurement.mPseudorangeInMeters;
- mPseudorangeUncertaintyInMeters = measurement.mPseudorangeUncertaintyInMeters;
- mCodePhaseInChips = measurement.mCodePhaseInChips;
- mCodePhaseUncertaintyInChips = measurement.mCodePhaseUncertaintyInChips;
- mCarrierFrequencyInHz = measurement.mCarrierFrequencyInHz;
+ mAccumulatedDeltaRangeMeters = measurement.mAccumulatedDeltaRangeMeters;
+ mAccumulatedDeltaRangeUncertaintyMeters =
+ measurement.mAccumulatedDeltaRangeUncertaintyMeters;
+ mCarrierFrequencyHz = measurement.mCarrierFrequencyHz;
mCarrierCycles = measurement.mCarrierCycles;
mCarrierPhase = measurement.mCarrierPhase;
mCarrierPhaseUncertainty = measurement.mCarrierPhaseUncertainty;
- mLossOfLock = measurement.mLossOfLock;
- mBitNumber = measurement.mBitNumber;
- mTimeFromLastBitInMs = measurement.mTimeFromLastBitInMs;
- mDopplerShiftInHz = measurement.mDopplerShiftInHz;
- mDopplerShiftUncertaintyInHz = measurement.mDopplerShiftUncertaintyInHz;
mMultipathIndicator = measurement.mMultipathIndicator;
mSnrInDb = measurement.mSnrInDb;
- mElevationInDeg = measurement.mElevationInDeg;
- mElevationUncertaintyInDeg = measurement.mElevationUncertaintyInDeg;
- mAzimuthInDeg = measurement.mAzimuthInDeg;
- mAzimuthUncertaintyInDeg = measurement.mAzimuthUncertaintyInDeg;
- mUsedInFix = measurement.mUsedInFix;
}
/**
@@ -244,14 +183,14 @@
* Gets the Pseudo-random number (PRN).
* Range: [1, 32]
*/
- public short getSvid() {
+ public int getSvid() {
return mSvid;
}
/**
* Sets the Pseud-random number (PRN).
*/
- public void setSvid(short value) {
+ public void setSvid(int value) {
mSvid = value;
}
@@ -259,14 +198,14 @@
* Getst the constellation type.
*/
@GnssStatus.ConstellationType
- public byte getConstellationType() {
+ public int getConstellationType() {
return mConstellationType;
}
/**
* Sets the constellation type.
*/
- public void setConstellationType(@GnssStatus.ConstellationType byte value) {
+ public void setConstellationType(@GnssStatus.ConstellationType int value) {
mConstellationType = value;
}
@@ -274,7 +213,7 @@
* Gets the time offset at which the measurement was taken in nanoseconds.
*
* The reference receiver's time from which this is offset is specified by
- * {@link GnssClock#getTimeInNs()}.
+ * {@link GnssClock#getTimeNanos()}.
*
* The sign of this value is given by the following equation:
* measurement time = time_ns + time_offset_ns
@@ -282,31 +221,31 @@
* The value provides an individual time-stamp for the measurement, and allows sub-nanosecond
* accuracy.
*/
- public double getTimeOffsetInNs() {
- return mTimeOffsetInNs;
+ public double getTimeOffsetNanos() {
+ return mTimeOffsetNanos;
}
/**
* Sets the time offset at which the measurement was taken in nanoseconds.
*/
- public void setTimeOffsetInNs(double value) {
- mTimeOffsetInNs = value;
+ public void setTimeOffsetNanos(double value) {
+ mTimeOffsetNanos = value;
}
/**
* Gets per-satellite sync state.
* It represents the current sync state for the associated satellite.
*
- * This value helps interpret {@link #getReceivedSvTimeInNs()}.
+ * This value helps interpret {@link #getReceivedSvTimeNanos()}.
*/
- public short getState() {
+ public int getState() {
return mState;
}
/**
* Sets the sync state.
*/
- public void setState(short value) {
+ public void setState(int value) {
mState = value;
}
@@ -408,29 +347,29 @@
* Symbol sync : [ 0 2ms ] : STATE_SYMBOL_SYNC is set
* Message : [ 0 1s ] : STATE_SBAS_SYNC is set
*/
- public long getReceivedSvTimeInNs() {
- return mReceivedSvTimeInNs;
+ public long getReceivedSvTimeNanos() {
+ return mReceivedSvTimeNanos;
}
/**
* Sets the received GNSS time in nanoseconds.
*/
- public void setReceivedSvTimeInNs(long value) {
- mReceivedSvTimeInNs = value;
+ public void setReceivedSvTimeNanos(long value) {
+ mReceivedSvTimeNanos = value;
}
/**
* Gets the received GNSS time uncertainty (1-Sigma) in nanoseconds.
*/
- public long getReceivedSvTimeUncertaintyInNs() {
- return mReceivedSvTimeUncertaintyInNs;
+ public long getReceivedSvTimeUncertaintyNanos() {
+ return mReceivedSvTimeUncertaintyNanos;
}
/**
* Sets the received GNSS time uncertainty (1-Sigma) in nanoseconds.
*/
- public void setReceivedSvTimeUncertaintyInNs(long value) {
- mReceivedSvTimeUncertaintyInNs = value;
+ public void setReceivedSvTimeUncertaintyNanos(long value) {
+ mReceivedSvTimeUncertaintyNanos = value;
}
/**
@@ -439,45 +378,46 @@
*
* The value contains the measured C/N0 for the signal at the antenna input.
*/
- public double getCn0InDbHz() {
- return mCn0InDbHz;
+ public double getCn0DbHz() {
+ return mCn0DbHz;
}
/**
* Sets the carrier-to-noise density in dB-Hz.
*/
- public void setCn0InDbHz(double value) {
- mCn0InDbHz = value;
+ public void setCn0DbHz(double value) {
+ mCn0DbHz = value;
}
/**
* Gets the Pseudorange rate at the timestamp in m/s.
- * The reported value includes {@link #getPseudorangeRateUncertaintyInMetersPerSec()}.
*
- * The correction of a given Pseudorange Rate value includes corrections from receiver and
- * satellite clock frequency errors.
- * {@link #isPseudorangeRateCorrected()} identifies the type of value reported.
+ * The reported value includes {@link #getPseudorangeRateUncertaintyMetersPerSecond()}.
*
- * A positive 'uncorrected' value indicates that the SV is moving away from the receiver.
- * The sign of the 'uncorrected' Pseudorange Rate and its relation to the sign of
- * {@link #getDopplerShiftInHz()} is given by the equation:
+ * The value is uncorrected, hence corrections for receiver and satellite clock frequency errors
+ * should not be included.
+ *
+ * A positive 'uncorrected' value indicates that the SV is moving away from the receiver. The
+ * sign of the 'uncorrected' 'pseudorange rate' and its relation to the sign of 'doppler shift'
+ * is given by the equation:
+ *
* pseudorange rate = -k * doppler shift (where k is a constant)
*/
- public double getPseudorangeRateInMetersPerSec() {
- return mPseudorangeRateInMetersPerSec;
+ public double getPseudorangeRateMetersPerSecond() {
+ return mPseudorangeRateMetersPerSecond;
}
/**
* Sets the pseudorange rate at the timestamp in m/s.
*/
- public void setPseudorangeRateInMetersPerSec(double value) {
- mPseudorangeRateInMetersPerSec = value;
+ public void setPseudorangeRateMetersPerSecond(double value) {
+ mPseudorangeRateMetersPerSecond = value;
}
/**
- * See {@link #getPseudorangeRateInMetersPerSec()} for more details.
+ * See {@link #getPseudorangeRateMetersPerSecond()} for more details.
*
- * @return {@code true} if {@link #getPseudorangeRateInMetersPerSec()} contains a corrected
+ * @return {@code true} if {@link #getPseudorangeRateMetersPerSecond()} contains a corrected
* value, {@code false} if it contains an uncorrected value.
*/
public boolean isPseudorangeRateCorrected() {
@@ -488,30 +428,30 @@
* Gets the pseudorange's rate uncertainty (1-Sigma) in m/s.
* The uncertainty is represented as an absolute (single sided) value.
*/
- public double getPseudorangeRateUncertaintyInMetersPerSec() {
- return mPseudorangeRateUncertaintyInMetersPerSec;
+ public double getPseudorangeRateUncertaintyMetersPerSecond() {
+ return mPseudorangeRateUncertaintyMetersPerSecond;
}
/**
* Sets the pseudorange's rate uncertainty (1-Sigma) in m/s.
*/
- public void setPseudorangeRateUncertaintyInMetersPerSec(double value) {
- mPseudorangeRateUncertaintyInMetersPerSec = value;
+ public void setPseudorangeRateUncertaintyMetersPerSecond(double value) {
+ mPseudorangeRateUncertaintyMetersPerSecond = value;
}
/**
* Gets 'Accumulated Delta Range' state.
- * It indicates whether {@link #getAccumulatedDeltaRangeInMeters()} is reset or there is a
+ * It indicates whether {@link #getAccumulatedDeltaRangeMeters()} is reset or there is a
* cycle slip (indicating 'loss of lock').
*/
- public short getAccumulatedDeltaRangeState() {
+ public int getAccumulatedDeltaRangeState() {
return mAccumulatedDeltaRangeState;
}
/**
* Sets the 'Accumulated Delta Range' state.
*/
- public void setAccumulatedDeltaRangeState(short value) {
+ public void setAccumulatedDeltaRangeState(int value) {
mAccumulatedDeltaRangeState = value;
}
@@ -545,24 +485,24 @@
/**
* Gets the accumulated delta range since the last channel reset, in meters.
- * The reported value includes {@link #getAccumulatedDeltaRangeUncertaintyInMeters()}.
+ * The reported value includes {@link #getAccumulatedDeltaRangeUncertaintyMeters()}.
*
* The availability of the value is represented by {@link #getAccumulatedDeltaRangeState()}.
*
* A positive value indicates that the SV is moving away from the receiver.
- * The sign of {@link #getAccumulatedDeltaRangeInMeters()} and its relation to the sign of
+ * The sign of {@link #getAccumulatedDeltaRangeMeters()} and its relation to the sign of
* {@link #getCarrierPhase()} is given by the equation:
* accumulated delta range = -k * carrier phase (where k is a constant)
*/
- public double getAccumulatedDeltaRangeInMeters() {
- return mAccumulatedDeltaRangeInMeters;
+ public double getAccumulatedDeltaRangeMeters() {
+ return mAccumulatedDeltaRangeMeters;
}
/**
* Sets the accumulated delta range in meters.
*/
- public void setAccumulatedDeltaRangeInMeters(double value) {
- mAccumulatedDeltaRangeInMeters = value;
+ public void setAccumulatedDeltaRangeMeters(double value) {
+ mAccumulatedDeltaRangeMeters = value;
}
/**
@@ -571,8 +511,8 @@
*
* The status of the value is represented by {@link #getAccumulatedDeltaRangeState()}.
*/
- public double getAccumulatedDeltaRangeUncertaintyInMeters() {
- return mAccumulatedDeltaRangeUncertaintyInMeters;
+ public double getAccumulatedDeltaRangeUncertaintyMeters() {
+ return mAccumulatedDeltaRangeUncertaintyMeters;
}
/**
@@ -580,149 +520,14 @@
*
* The status of the value is represented by {@link #getAccumulatedDeltaRangeState()}.
*/
- public void setAccumulatedDeltaRangeUncertaintyInMeters(double value) {
- mAccumulatedDeltaRangeUncertaintyInMeters = value;
+ public void setAccumulatedDeltaRangeUncertaintyMeters(double value) {
+ mAccumulatedDeltaRangeUncertaintyMeters = value;
}
/**
- * Returns true if {@link #getPseudorangeInMeters()} is available, false otherwise.
+ * Returns true if {@link #getCarrierFrequencyHz()} is available, false otherwise.
*/
- public boolean hasPseudorangeInMeters() {
- return isFlagSet(HAS_PSEUDORANGE);
- }
-
- /**
- * Gets the best derived pseudorange by the chipset, in meters.
- * The reported pseudorange includes {@link #getPseudorangeUncertaintyInMeters()}.
- *
- * The value is only available if {@link #hasPseudorangeInMeters()} is true.
- */
- public double getPseudorangeInMeters() {
- return mPseudorangeInMeters;
- }
-
- /**
- * Sets the Pseudo-range in meters.
- */
- public void setPseudorangeInMeters(double value) {
- setFlag(HAS_PSEUDORANGE);
- mPseudorangeInMeters = value;
- }
-
- /**
- * Resets the Pseudo-range in meters.
- */
- public void resetPseudorangeInMeters() {
- resetFlag(HAS_PSEUDORANGE);
- mPseudorangeInMeters = Double.NaN;
- }
-
- /**
- * Returns true if {@link #getPseudorangeUncertaintyInMeters()} is available, false otherwise.
- */
- public boolean hasPseudorangeUncertaintyInMeters() {
- return isFlagSet(HAS_PSEUDORANGE_UNCERTAINTY);
- }
-
- /**
- * Gets the pseudorange's uncertainty (1-Sigma) in meters.
- * The value contains the 'pseudorange' and 'clock' uncertainty in it.
- * The uncertainty is represented as an absolute (single sided) value.
- *
- * The value is only available if {@link #hasPseudorangeUncertaintyInMeters()} is true.
- */
- public double getPseudorangeUncertaintyInMeters() {
- return mPseudorangeUncertaintyInMeters;
- }
-
- /**
- * Sets the pseudo-range's uncertainty (1-Sigma) in meters.
- */
- public void setPseudorangeUncertaintyInMeters(double value) {
- setFlag(HAS_PSEUDORANGE_UNCERTAINTY);
- mPseudorangeUncertaintyInMeters = value;
- }
-
- /**
- * Resets the pseudo-range's uncertainty (1-Sigma) in meters.
- */
- public void resetPseudorangeUncertaintyInMeters() {
- resetFlag(HAS_PSEUDORANGE_UNCERTAINTY);
- mPseudorangeUncertaintyInMeters = Double.NaN;
- }
-
- /**
- * Returns true if {@link #getCodePhaseInChips()} is available, false otherwise.
- */
- public boolean hasCodePhaseInChips() {
- return isFlagSet(HAS_CODE_PHASE);
- }
-
- /**
- * Gets the fraction of the current C/A code cycle.
- * Range: [0, 1023]
- * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}.
- * The reported code-phase includes {@link #getCodePhaseUncertaintyInChips()}.
- *
- * The value is only available if {@link #hasCodePhaseInChips()} is true.
- */
- public double getCodePhaseInChips() {
- return mCodePhaseInChips;
- }
-
- /**
- * Sets the Code-phase in chips.
- */
- public void setCodePhaseInChips(double value) {
- setFlag(HAS_CODE_PHASE);
- mCodePhaseInChips = value;
- }
-
- /**
- * Resets the Code-phase in chips.
- */
- public void resetCodePhaseInChips() {
- resetFlag(HAS_CODE_PHASE);
- mCodePhaseInChips = Double.NaN;
- }
-
- /**
- * Returns true if {@link #getCodePhaseUncertaintyInChips()} is available, false otherwise.
- */
- public boolean hasCodePhaseUncertaintyInChips() {
- return isFlagSet(HAS_CODE_PHASE_UNCERTAINTY);
- }
-
- /**
- * Gets the code-phase's uncertainty (1-Sigma) as a fraction of chips.
- * The uncertainty is represented as an absolute (single sided) value.
- *
- * The value is only available if {@link #hasCodePhaseUncertaintyInChips()} is true.
- */
- public double getCodePhaseUncertaintyInChips() {
- return mCodePhaseUncertaintyInChips;
- }
-
- /**
- * Sets the Code-phase's uncertainty (1-Sigma) in fractions of chips.
- */
- public void setCodePhaseUncertaintyInChips(double value) {
- setFlag(HAS_CODE_PHASE_UNCERTAINTY);
- mCodePhaseUncertaintyInChips = value;
- }
-
- /**
- * Resets the Code-phase's uncertainty (1-Sigma) in fractions of chips.
- */
- public void resetCodePhaseUncertaintyInChips() {
- resetFlag(HAS_CODE_PHASE_UNCERTAINTY);
- mCodePhaseUncertaintyInChips = Double.NaN;
- }
-
- /**
- * Returns true if {@link #getCarrierFrequencyInHz()} is available, false otherwise.
- */
- public boolean hasCarrierFrequencyInHz() {
+ public boolean hasCarrierFrequencyHz() {
return isFlagSet(HAS_CARRIER_FREQUENCY);
}
@@ -730,26 +535,26 @@
* Gets the carrier frequency at which codes and messages are modulated, it can be L1 or L2.
* If the field is not set, the carrier frequency corresponds to L1.
*
- * The value is only available if {@link #hasCarrierFrequencyInHz()} is true.
+ * The value is only available if {@link #hasCarrierFrequencyHz()} is true.
*/
- public float getCarrierFrequencyInHz() {
- return mCarrierFrequencyInHz;
+ public float getCarrierFrequencyHz() {
+ return mCarrierFrequencyHz;
}
/**
* Sets the Carrier frequency (L1 or L2) in Hz.
*/
- public void setCarrierFrequencyInHz(float carrierFrequencyInHz) {
+ public void setCarrierFrequencyHz(float carrierFrequencyHz) {
setFlag(HAS_CARRIER_FREQUENCY);
- mCarrierFrequencyInHz = carrierFrequencyInHz;
+ mCarrierFrequencyHz = carrierFrequencyHz;
}
/**
* Resets the Carrier frequency (L1 or L2) in Hz.
*/
- public void resetCarrierFrequencyInHz() {
+ public void resetCarrierFrequencyHz() {
resetFlag(HAS_CARRIER_FREQUENCY);
- mCarrierFrequencyInHz = Float.NaN;
+ mCarrierFrequencyHz = Float.NaN;
}
/**
@@ -761,7 +566,7 @@
/**
* The number of full carrier cycles between the satellite and the receiver.
- * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}.
+ * The reference frequency is given by the value of {@link #getCarrierFrequencyHz()}.
*
* The value is only available if {@link #hasCarrierCycles()} is true.
*/
@@ -797,7 +602,7 @@
* Range: [0.0, 1.0].
* This is usually the fractional part of the complete carrier phase measurement.
*
- * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}.
+ * The reference frequency is given by the value of {@link #getCarrierFrequencyHz()}.
* The reported carrier-phase includes {@link #getCarrierPhaseUncertainty()}.
*
* The value is only available if {@link #hasCarrierPhase()} is true.
@@ -856,183 +661,17 @@
}
/**
- * Gets a value indicating the 'loss of lock' state of the event.
- */
- @LossOfLockStatus
- public byte getLossOfLock() {
- return mLossOfLock;
- }
-
- /**
- * Sets the 'loss of lock' status.
- */
- public void setLossOfLock(@LossOfLockStatus byte value) {
- mLossOfLock = value;
- }
-
- /**
- * Gets a string representation of the 'loss of lock'.
- * For internal and logging use only.
- */
- private String getLossOfLockString() {
- switch (mLossOfLock) {
- case LOSS_OF_LOCK_UNKNOWN:
- return "Unknown";
- case LOSS_OF_LOCK_OK:
- return "Ok";
- case LOSS_OF_LOCK_CYCLE_SLIP:
- return "CycleSlip";
- default:
- return "<Invalid:" + mLossOfLock + ">";
- }
- }
-
- /**
- * Returns true if {@link #getBitNumber()} is available, false otherwise.
- */
- public boolean hasBitNumber() {
- return isFlagSet(HAS_BIT_NUMBER);
- }
-
- /**
- * Gets the number of GPS bits transmitted since Sat-Sun midnight (GPS week).
- *
- * The value is only available if {@link #hasBitNumber()} is true.
- */
- public int getBitNumber() {
- return mBitNumber;
- }
-
- /**
- * Sets the bit number within the broadcast frame.
- */
- public void setBitNumber(int bitNumber) {
- setFlag(HAS_BIT_NUMBER);
- mBitNumber = bitNumber;
- }
-
- /**
- * Resets the bit number within the broadcast frame.
- */
- public void resetBitNumber() {
- resetFlag(HAS_BIT_NUMBER);
- mBitNumber = Integer.MIN_VALUE;
- }
-
- /**
- * Returns true if {@link #getTimeFromLastBitInMs()} is available, false otherwise.
- */
- public boolean hasTimeFromLastBitInMs() {
- return isFlagSet(HAS_TIME_FROM_LAST_BIT);
- }
-
- /**
- * Gets the elapsed time since the last received bit in milliseconds.
- * Range: [0, 20].
- *
- * The value is only available if {@link #hasTimeFromLastBitInMs()} is true.
- */
- public short getTimeFromLastBitInMs() {
- return mTimeFromLastBitInMs;
- }
-
- /**
- * Sets the elapsed time since the last received bit in milliseconds.
- */
- public void setTimeFromLastBitInMs(short value) {
- setFlag(HAS_TIME_FROM_LAST_BIT);
- mTimeFromLastBitInMs = value;
- }
-
- /**
- * Resets the elapsed time since the last received bit in milliseconds.
- */
- public void resetTimeFromLastBitInMs() {
- resetFlag(HAS_TIME_FROM_LAST_BIT);
- mTimeFromLastBitInMs = Short.MIN_VALUE;
- }
-
- /**
- * Returns true if {@link #getDopplerShiftInHz()} is available, false otherwise.
- */
- public boolean hasDopplerShiftInHz() {
- return isFlagSet(HAS_DOPPLER_SHIFT);
- }
-
- /**
- * Gets the Doppler Shift in Hz.
- * A positive value indicates that the SV is moving toward the receiver.
- *
- * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}.
- * The reported doppler shift includes {@link #getDopplerShiftUncertaintyInHz()}.
- *
- * The value is only available if {@link #hasDopplerShiftInHz()} is true.
- */
- public double getDopplerShiftInHz() {
- return mDopplerShiftInHz;
- }
-
- /**
- * Sets the Doppler shift in Hz.
- */
- public void setDopplerShiftInHz(double value) {
- setFlag(HAS_DOPPLER_SHIFT);
- mDopplerShiftInHz = value;
- }
-
- /**
- * Resets the Doppler shift in Hz.
- */
- public void resetDopplerShiftInHz() {
- resetFlag(HAS_DOPPLER_SHIFT);
- mDopplerShiftInHz = Double.NaN;
- }
-
- /**
- * Returns true if {@link #getDopplerShiftUncertaintyInHz()} is available, false otherwise.
- */
- public boolean hasDopplerShiftUncertaintyInHz() {
- return isFlagSet(HAS_DOPPLER_SHIFT_UNCERTAINTY);
- }
-
- /**
- * Gets the Doppler's Shift uncertainty (1-Sigma) in Hz.
- * The uncertainty is represented as an absolute (single sided) value.
- *
- * The value is only available if {@link #hasDopplerShiftUncertaintyInHz()} is true.
- */
- public double getDopplerShiftUncertaintyInHz() {
- return mDopplerShiftUncertaintyInHz;
- }
-
- /**
- * Sets the Doppler's shift uncertainty (1-Sigma) in Hz.
- */
- public void setDopplerShiftUncertaintyInHz(double value) {
- setFlag(HAS_DOPPLER_SHIFT_UNCERTAINTY);
- mDopplerShiftUncertaintyInHz = value;
- }
-
- /**
- * Resets the Doppler's shift uncertainty (1-Sigma) in Hz.
- */
- public void resetDopplerShiftUncertaintyInHz() {
- resetFlag(HAS_DOPPLER_SHIFT_UNCERTAINTY);
- mDopplerShiftUncertaintyInHz = Double.NaN;
- }
-
- /**
* Gets a value indicating the 'multipath' state of the event.
*/
@MultipathIndicator
- public byte getMultipathIndicator() {
+ public int getMultipathIndicator() {
return mMultipathIndicator;
}
/**
* Sets the 'multi-path' indicator.
*/
- public void setMultipathIndicator(@MultipathIndicator byte value) {
+ public void setMultipathIndicator(@MultipathIndicator int value) {
mMultipathIndicator = value;
}
@@ -1085,200 +724,30 @@
mSnrInDb = Double.NaN;
}
- /**
- * Returns true if {@link #getElevationInDeg()} is available, false otherwise.
- */
- public boolean hasElevationInDeg() {
- return isFlagSet(HAS_ELEVATION);
- }
-
- /**
- * Gets the Elevation in degrees.
- * Range: [-90, 90]
- * The reported elevation includes {@link #getElevationUncertaintyInDeg()}.
- *
- * The value is only available if {@link #hasElevationInDeg()} is true.
- */
- public double getElevationInDeg() {
- return mElevationInDeg;
- }
-
- /**
- * Sets the Elevation in degrees.
- */
- public void setElevationInDeg(double elevationInDeg) {
- setFlag(HAS_ELEVATION);
- mElevationInDeg = elevationInDeg;
- }
-
- /**
- * Resets the Elevation in degrees.
- */
- public void resetElevationInDeg() {
- resetFlag(HAS_ELEVATION);
- mElevationInDeg = Double.NaN;
- }
-
- /**
- * Returns true if {@link #getElevationUncertaintyInDeg()} is available, false otherwise.
- */
- public boolean hasElevationUncertaintyInDeg() {
- return isFlagSet(HAS_ELEVATION_UNCERTAINTY);
- }
-
- /**
- * Gets the elevation's uncertainty (1-Sigma) in degrees.
- * Range: [0, 90]
- *
- * The uncertainty is represented as an absolute (single sided) value.
- *
- * The value is only available if {@link #hasElevationUncertaintyInDeg()} is true.
- */
- public double getElevationUncertaintyInDeg() {
- return mElevationUncertaintyInDeg;
- }
-
- /**
- * Sets the elevation's uncertainty (1-Sigma) in degrees.
- */
- public void setElevationUncertaintyInDeg(double value) {
- setFlag(HAS_ELEVATION_UNCERTAINTY);
- mElevationUncertaintyInDeg = value;
- }
-
- /**
- * Resets the elevation's uncertainty (1-Sigma) in degrees.
- */
- public void resetElevationUncertaintyInDeg() {
- resetFlag(HAS_ELEVATION_UNCERTAINTY);
- mElevationUncertaintyInDeg = Double.NaN;
- }
-
- /**
- * Returns true if {@link #getAzimuthInDeg()} is available, false otherwise.
- */
- public boolean hasAzimuthInDeg() {
- return isFlagSet(HAS_AZIMUTH);
- }
-
- /**
- * Gets the azimuth in degrees.
- * Range: [0, 360).
- *
- * The reported azimuth includes {@link #getAzimuthUncertaintyInDeg()}.
- *
- * The value is only available if {@link #hasAzimuthInDeg()} is true.
- */
- public double getAzimuthInDeg() {
- return mAzimuthInDeg;
- }
-
- /**
- * Sets the Azimuth in degrees.
- */
- public void setAzimuthInDeg(double value) {
- setFlag(HAS_AZIMUTH);
- mAzimuthInDeg = value;
- }
-
- /**
- * Resets the Azimuth in degrees.
- */
- public void resetAzimuthInDeg() {
- resetFlag(HAS_AZIMUTH);
- mAzimuthInDeg = Double.NaN;
- }
-
- /**
- * Returns true if {@link #getAzimuthUncertaintyInDeg()} is available, false otherwise.
- */
- public boolean hasAzimuthUncertaintyInDeg() {
- return isFlagSet(HAS_AZIMUTH_UNCERTAINTY);
- }
-
- /**
- * Gets the azimuth's uncertainty (1-Sigma) in degrees.
- * Range: [0, 180].
- *
- * The uncertainty is represented as an absolute (single sided) value.
- *
- * The value is only available if {@link #hasAzimuthUncertaintyInDeg()} is true.
- */
- public double getAzimuthUncertaintyInDeg() {
- return mAzimuthUncertaintyInDeg;
- }
-
- /**
- * Sets the Azimuth's uncertainty (1-Sigma) in degrees.
- */
- public void setAzimuthUncertaintyInDeg(double value) {
- setFlag(HAS_AZIMUTH_UNCERTAINTY);
- mAzimuthUncertaintyInDeg = value;
- }
-
- /**
- * Resets the Azimuth's uncertainty (1-Sigma) in degrees.
- */
- public void resetAzimuthUncertaintyInDeg() {
- resetFlag(HAS_AZIMUTH_UNCERTAINTY);
- mAzimuthUncertaintyInDeg = Double.NaN;
- }
-
- /**
- * Gets a flag indicating whether the GNSS represented by the measurement was used for computing
- * the most recent fix.
- *
- * @return A non-null value if the data is available, null otherwise.
- */
- public boolean isUsedInFix() {
- return mUsedInFix;
- }
-
- /**
- * Sets the Used-in-Fix flag.
- */
- public void setUsedInFix(boolean value) {
- mUsedInFix = value;
- }
-
public static final Creator<GnssMeasurement> CREATOR = new Creator<GnssMeasurement>() {
@Override
public GnssMeasurement createFromParcel(Parcel parcel) {
GnssMeasurement gnssMeasurement = new GnssMeasurement();
gnssMeasurement.mFlags = parcel.readInt();
- gnssMeasurement.mSvid = (short) parcel.readInt();
- gnssMeasurement.mConstellationType = parcel.readByte();
- gnssMeasurement.mTimeOffsetInNs = parcel.readDouble();
- gnssMeasurement.mState = (short) parcel.readInt();
- gnssMeasurement.mReceivedSvTimeInNs = parcel.readLong();
- gnssMeasurement.mReceivedSvTimeUncertaintyInNs = parcel.readLong();
- gnssMeasurement.mCn0InDbHz = parcel.readDouble();
- gnssMeasurement.mPseudorangeRateInMetersPerSec = parcel.readDouble();
- gnssMeasurement.mPseudorangeRateUncertaintyInMetersPerSec = parcel.readDouble();
- gnssMeasurement.mAccumulatedDeltaRangeState = (short) parcel.readInt();
- gnssMeasurement.mAccumulatedDeltaRangeInMeters = parcel.readDouble();
- gnssMeasurement.mAccumulatedDeltaRangeUncertaintyInMeters = parcel.readDouble();
- gnssMeasurement.mPseudorangeInMeters = parcel.readDouble();
- gnssMeasurement.mPseudorangeUncertaintyInMeters = parcel.readDouble();
- gnssMeasurement.mCodePhaseInChips = parcel.readDouble();
- gnssMeasurement.mCodePhaseUncertaintyInChips = parcel.readDouble();
- gnssMeasurement.mCarrierFrequencyInHz = parcel.readFloat();
+ gnssMeasurement.mSvid = parcel.readInt();
+ gnssMeasurement.mConstellationType = parcel.readInt();
+ gnssMeasurement.mTimeOffsetNanos = parcel.readDouble();
+ gnssMeasurement.mState = parcel.readInt();
+ gnssMeasurement.mReceivedSvTimeNanos = parcel.readLong();
+ gnssMeasurement.mReceivedSvTimeUncertaintyNanos = parcel.readLong();
+ gnssMeasurement.mCn0DbHz = parcel.readDouble();
+ gnssMeasurement.mPseudorangeRateMetersPerSecond = parcel.readDouble();
+ gnssMeasurement.mPseudorangeRateUncertaintyMetersPerSecond = parcel.readDouble();
+ gnssMeasurement.mAccumulatedDeltaRangeState = parcel.readInt();
+ gnssMeasurement.mAccumulatedDeltaRangeMeters = parcel.readDouble();
+ gnssMeasurement.mAccumulatedDeltaRangeUncertaintyMeters = parcel.readDouble();
+ gnssMeasurement.mCarrierFrequencyHz = parcel.readFloat();
gnssMeasurement.mCarrierCycles = parcel.readLong();
gnssMeasurement.mCarrierPhase = parcel.readDouble();
gnssMeasurement.mCarrierPhaseUncertainty = parcel.readDouble();
- gnssMeasurement.mLossOfLock = parcel.readByte();
- gnssMeasurement.mBitNumber = parcel.readInt();
- gnssMeasurement.mTimeFromLastBitInMs = (short) parcel.readInt();
- gnssMeasurement.mDopplerShiftInHz = parcel.readDouble();
- gnssMeasurement.mDopplerShiftUncertaintyInHz = parcel.readDouble();
- gnssMeasurement.mMultipathIndicator = parcel.readByte();
+ gnssMeasurement.mMultipathIndicator = parcel.readInt();
gnssMeasurement.mSnrInDb = parcel.readDouble();
- gnssMeasurement.mElevationInDeg = parcel.readDouble();
- gnssMeasurement.mElevationUncertaintyInDeg = parcel.readDouble();
- gnssMeasurement.mAzimuthInDeg = parcel.readDouble();
- gnssMeasurement.mAzimuthUncertaintyInDeg = parcel.readDouble();
- gnssMeasurement.mUsedInFix = parcel.readInt() != 0;
return gnssMeasurement;
}
@@ -1293,37 +762,23 @@
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mFlags);
parcel.writeInt(mSvid);
- parcel.writeByte(mConstellationType);
- parcel.writeDouble(mTimeOffsetInNs);
+ parcel.writeInt(mConstellationType);
+ parcel.writeDouble(mTimeOffsetNanos);
parcel.writeInt(mState);
- parcel.writeLong(mReceivedSvTimeInNs);
- parcel.writeLong(mReceivedSvTimeUncertaintyInNs);
- parcel.writeDouble(mCn0InDbHz);
- parcel.writeDouble(mPseudorangeRateInMetersPerSec);
- parcel.writeDouble(mPseudorangeRateUncertaintyInMetersPerSec);
+ parcel.writeLong(mReceivedSvTimeNanos);
+ parcel.writeLong(mReceivedSvTimeUncertaintyNanos);
+ parcel.writeDouble(mCn0DbHz);
+ parcel.writeDouble(mPseudorangeRateMetersPerSecond);
+ parcel.writeDouble(mPseudorangeRateUncertaintyMetersPerSecond);
parcel.writeInt(mAccumulatedDeltaRangeState);
- parcel.writeDouble(mAccumulatedDeltaRangeInMeters);
- parcel.writeDouble(mAccumulatedDeltaRangeUncertaintyInMeters);
- parcel.writeDouble(mPseudorangeInMeters);
- parcel.writeDouble(mPseudorangeUncertaintyInMeters);
- parcel.writeDouble(mCodePhaseInChips);
- parcel.writeDouble(mCodePhaseUncertaintyInChips);
- parcel.writeFloat(mCarrierFrequencyInHz);
+ parcel.writeDouble(mAccumulatedDeltaRangeMeters);
+ parcel.writeDouble(mAccumulatedDeltaRangeUncertaintyMeters);
+ parcel.writeFloat(mCarrierFrequencyHz);
parcel.writeLong(mCarrierCycles);
parcel.writeDouble(mCarrierPhase);
parcel.writeDouble(mCarrierPhaseUncertainty);
- parcel.writeByte(mLossOfLock);
- parcel.writeInt(mBitNumber);
- parcel.writeInt(mTimeFromLastBitInMs);
- parcel.writeDouble(mDopplerShiftInHz);
- parcel.writeDouble(mDopplerShiftUncertaintyInHz);
- parcel.writeByte(mMultipathIndicator);
+ parcel.writeInt(mMultipathIndicator);
parcel.writeDouble(mSnrInDb);
- parcel.writeDouble(mElevationInDeg);
- parcel.writeDouble(mElevationUncertaintyInDeg);
- parcel.writeDouble(mAzimuthInDeg);
- parcel.writeDouble(mAzimuthUncertaintyInDeg);
- parcel.writeInt(mUsedInFix ? 1 : 0);
}
@Override
@@ -1339,25 +794,25 @@
builder.append(String.format(format, "Svid", mSvid));
builder.append(String.format(format, "ConstellationType", mConstellationType));
- builder.append(String.format(format, "TimeOffsetInNs", mTimeOffsetInNs));
+ builder.append(String.format(format, "TimeOffsetNanos", mTimeOffsetNanos));
builder.append(String.format(format, "State", getStateString()));
builder.append(String.format(
formatWithUncertainty,
- "ReceivedSvTimeInNs",
- mReceivedSvTimeInNs,
- "ReceivedSvTimeUncertaintyInNs",
- mReceivedSvTimeUncertaintyInNs));
+ "ReceivedSvTimeNanos",
+ mReceivedSvTimeNanos,
+ "ReceivedSvTimeUncertaintyNanos",
+ mReceivedSvTimeUncertaintyNanos));
- builder.append(String.format(format, "Cn0InDbHz", mCn0InDbHz));
+ builder.append(String.format(format, "Cn0DbHz", mCn0DbHz));
builder.append(String.format(
formatWithUncertainty,
- "PseudorangeRateInMetersPerSec",
- mPseudorangeRateInMetersPerSec,
- "PseudorangeRateUncertaintyInMetersPerSec",
- mPseudorangeRateUncertaintyInMetersPerSec));
+ "PseudorangeRateMetersPerSecond",
+ mPseudorangeRateMetersPerSecond,
+ "PseudorangeRateUncertaintyMetersPerSecond",
+ mPseudorangeRateUncertaintyMetersPerSecond));
builder.append(String.format(
format,
"PseudorangeRateIsCorrected",
@@ -1370,29 +825,15 @@
builder.append(String.format(
formatWithUncertainty,
- "AccumulatedDeltaRangeInMeters",
- mAccumulatedDeltaRangeInMeters,
- "AccumulatedDeltaRangeUncertaintyInMeters",
- mAccumulatedDeltaRangeUncertaintyInMeters));
-
- builder.append(String.format(
- formatWithUncertainty,
- "PseudorangeInMeters",
- hasPseudorangeInMeters() ? mPseudorangeInMeters : null,
- "PseudorangeUncertaintyInMeters",
- hasPseudorangeUncertaintyInMeters() ? mPseudorangeUncertaintyInMeters : null));
-
- builder.append(String.format(
- formatWithUncertainty,
- "CodePhaseInChips",
- hasCodePhaseInChips() ? mCodePhaseInChips : null,
- "CodePhaseUncertaintyInChips",
- hasCodePhaseUncertaintyInChips() ? mCodePhaseUncertaintyInChips : null));
+ "AccumulatedDeltaRangeMeters",
+ mAccumulatedDeltaRangeMeters,
+ "AccumulatedDeltaRangeUncertaintyMeters",
+ mAccumulatedDeltaRangeUncertaintyMeters));
builder.append(String.format(
format,
- "CarrierFrequencyInHz",
- hasCarrierFrequencyInHz() ? mCarrierFrequencyInHz : null));
+ "CarrierFrequencyHz",
+ hasCarrierFrequencyHz() ? mCarrierFrequencyHz : null));
builder.append(String.format(
format,
@@ -1406,25 +847,6 @@
"CarrierPhaseUncertainty",
hasCarrierPhaseUncertainty() ? mCarrierPhaseUncertainty : null));
- builder.append(String.format(format, "LossOfLock", getLossOfLockString()));
-
- builder.append(String.format(
- format,
- "BitNumber",
- hasBitNumber() ? mBitNumber : null));
-
- builder.append(String.format(
- format,
- "TimeFromLastBitInMs",
- hasTimeFromLastBitInMs() ? mTimeFromLastBitInMs : null));
-
- builder.append(String.format(
- formatWithUncertainty,
- "DopplerShiftInHz",
- hasDopplerShiftInHz() ? mDopplerShiftInHz : null,
- "DopplerShiftUncertaintyInHz",
- hasDopplerShiftUncertaintyInHz() ? mDopplerShiftUncertaintyInHz : null));
-
builder.append(String.format(format, "MultipathIndicator", getMultipathIndicatorString()));
builder.append(String.format(
@@ -1432,58 +854,28 @@
"SnrInDb",
hasSnrInDb() ? mSnrInDb : null));
- builder.append(String.format(
- formatWithUncertainty,
- "ElevationInDeg",
- hasElevationInDeg() ? mElevationInDeg : null,
- "ElevationUncertaintyInDeg",
- hasElevationUncertaintyInDeg() ? mElevationUncertaintyInDeg : null));
-
- builder.append(String.format(
- formatWithUncertainty,
- "AzimuthInDeg",
- hasAzimuthInDeg() ? mAzimuthInDeg : null,
- "AzimuthUncertaintyInDeg",
- hasAzimuthUncertaintyInDeg() ? mAzimuthUncertaintyInDeg : null));
-
- builder.append(String.format(format, "UsedInFix", mUsedInFix));
-
return builder.toString();
}
private void initialize() {
mFlags = HAS_NO_FLAGS;
- setSvid((short) 0);
- setTimeOffsetInNs(Long.MIN_VALUE);
+ setSvid(0);
+ setTimeOffsetNanos(Long.MIN_VALUE);
setState(STATE_UNKNOWN);
- setReceivedSvTimeInNs(Long.MIN_VALUE);
- setReceivedSvTimeUncertaintyInNs(Long.MAX_VALUE);
- setCn0InDbHz(Double.MIN_VALUE);
- setPseudorangeRateInMetersPerSec(Double.MIN_VALUE);
- setPseudorangeRateUncertaintyInMetersPerSec(Double.MIN_VALUE);
+ setReceivedSvTimeNanos(Long.MIN_VALUE);
+ setReceivedSvTimeUncertaintyNanos(Long.MAX_VALUE);
+ setCn0DbHz(Double.MIN_VALUE);
+ setPseudorangeRateMetersPerSecond(Double.MIN_VALUE);
+ setPseudorangeRateUncertaintyMetersPerSecond(Double.MIN_VALUE);
setAccumulatedDeltaRangeState(ADR_STATE_UNKNOWN);
- setAccumulatedDeltaRangeInMeters(Double.MIN_VALUE);
- setAccumulatedDeltaRangeUncertaintyInMeters(Double.MIN_VALUE);
- resetPseudorangeInMeters();
- resetPseudorangeUncertaintyInMeters();
- resetCodePhaseInChips();
- resetCodePhaseUncertaintyInChips();
- resetCarrierFrequencyInHz();
+ setAccumulatedDeltaRangeMeters(Double.MIN_VALUE);
+ setAccumulatedDeltaRangeUncertaintyMeters(Double.MIN_VALUE);
+ resetCarrierFrequencyHz();
resetCarrierCycles();
resetCarrierPhase();
resetCarrierPhaseUncertainty();
- setLossOfLock(LOSS_OF_LOCK_UNKNOWN);
- resetBitNumber();
- resetTimeFromLastBitInMs();
- resetDopplerShiftInHz();
- resetDopplerShiftUncertaintyInHz();
setMultipathIndicator(MULTIPATH_INDICATOR_UNKNOWN);
resetSnrInDb();
- resetElevationInDeg();
- resetElevationUncertaintyInDeg();
- resetAzimuthInDeg();
- resetAzimuthUncertaintyInDeg();
- setUsedInFix(false);
}
private void setFlag(int flag) {
diff --git a/location/java/android/location/GnssMeasurementsEvent.java b/location/java/android/location/GnssMeasurementsEvent.java
index b744a03..86841ff 100644
--- a/location/java/android/location/GnssMeasurementsEvent.java
+++ b/location/java/android/location/GnssMeasurementsEvent.java
@@ -33,46 +33,46 @@
* Events are delivered to registered instances of {@link Callback}.
*/
public final class GnssMeasurementsEvent implements Parcelable {
- /** The status of GPS measurements event. */
+ /** The status of GNSS measurements event. */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GPS_LOCATION_DISABLED})
+ @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GNSS_LOCATION_DISABLED})
public @interface GnssMeasurementsStatus {}
/**
- * The system does not support tracking of GPS Measurements. This status will not change in the
+ * The system does not support tracking of GNSS Measurements. This status will not change in the
* future.
*/
public static final int STATUS_NOT_SUPPORTED = 0;
/**
- * GPS Measurements are successfully being tracked, it will receive updates once they are
+ * GNSS Measurements are successfully being tracked, it will receive updates once they are
* available.
*/
public static final int STATUS_READY = 1;
/**
- * GPS provider or Location is disabled, updates will not be received until they are enabled.
+ * GNSS provider or Location is disabled, updates will not be received until they are enabled.
*/
- public static final int STATUS_GPS_LOCATION_DISABLED = 2;
+ public static final int STATUS_GNSS_LOCATION_DISABLED = 2;
private final GnssClock mClock;
private final Collection<GnssMeasurement> mReadOnlyMeasurements;
/**
- * Used for receiving GPS satellite measurements from the GPS engine.
+ * Used for receiving GNSS satellite measurements from the GNSS engine.
* Each measurement contains raw and computed data identifying a satellite.
* You can implement this interface and call
- * {@link LocationManager#registerGnssMeasurementCallback}.
+ * {@link LocationManager#registerGnssMeasurementsCallback}.
*/
public static abstract class Callback {
/**
- * Returns the latest collected GPS Measurements.
+ * Reports the latest collected GNSS Measurements.
*/
public void onGnssMeasurementsReceived(GnssMeasurementsEvent eventArgs) {}
/**
- * Returns the latest status of the GPS Measurements sub-system.
+ * Reports the latest status of the GNSS Measurements sub-system.
*/
public void onStatusChanged(@GnssMeasurementsStatus int status) {}
}
diff --git a/location/java/android/location/GnssNavigationMessage.java b/location/java/android/location/GnssNavigationMessage.java
index faefd0bb..c0608e0 100644
--- a/location/java/android/location/GnssNavigationMessage.java
+++ b/location/java/android/location/GnssNavigationMessage.java
@@ -34,58 +34,57 @@
/** The type of the GPS Clock. */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({MESSAGE_TYPE_UNKNOWN, MESSAGE_TYPE_GPS_L1CA, MESSAGE_TYPE_GPS_L2CNAV,
- MESSAGE_TYPE_GPS_L5CNAV, MESSAGE_TYPE_GPS_CNAV2, MESSAGE_TYPE_GLO_L1CA, MESSAGE_TYPE_BDS_D1,
- MESSAGE_TYPE_BDS_D2, MESSAGE_TYPE_GAL_I, MESSAGE_TYPE_GAL_F})
+ @IntDef({TYPE_UNKNOWN, TYPE_GPS_L1CA, TYPE_GPS_L2CNAV, TYPE_GPS_L5CNAV, TYPE_GPS_CNAV2,
+ TYPE_GLO_L1CA, TYPE_BDS_D1, TYPE_BDS_D2, TYPE_GAL_I, TYPE_GAL_F})
public @interface GnssNavigationMessageType {}
// The following enumerations must be in sync with the values declared in gps.h
/** Message type unknown */
- public static final short MESSAGE_TYPE_UNKNOWN = 0;
+ public static final int TYPE_UNKNOWN = 0;
/** GPS L1 C/A message contained in the structure. */
- public static final short MESSAGE_TYPE_GPS_L1CA = 0x0101;
+ public static final int TYPE_GPS_L1CA = 0x0101;
/** GPS L2-CNAV message contained in the structure. */
- public static final short MESSAGE_TYPE_GPS_L2CNAV = 0x0102;
+ public static final int TYPE_GPS_L2CNAV = 0x0102;
/** GPS L5-CNAV message contained in the structure. */
- public static final short MESSAGE_TYPE_GPS_L5CNAV = 0x0103;
+ public static final int TYPE_GPS_L5CNAV = 0x0103;
/** GPS CNAV-2 message contained in the structure. */
- public static final short MESSAGE_TYPE_GPS_CNAV2 = 0x0104;
+ public static final int TYPE_GPS_CNAV2 = 0x0104;
/** Glonass L1 CA message contained in the structure. */
- public static final short MESSAGE_TYPE_GLO_L1CA = 0x0301;
+ public static final int TYPE_GLO_L1CA = 0x0301;
/** Beidou D1 message contained in the structure. */
- public static final short MESSAGE_TYPE_BDS_D1 = 0x0501;
+ public static final int TYPE_BDS_D1 = 0x0501;
/** Beidou D2 message contained in the structure. */
- public static final short MESSAGE_TYPE_BDS_D2 = 0x0502;
+ public static final int TYPE_BDS_D2 = 0x0502;
/** Galileo I/NAV message contained in the structure. */
- public static final short MESSAGE_TYPE_GAL_I = 0x0601;
+ public static final int TYPE_GAL_I = 0x0601;
/** Galileo F/NAV message contained in the structure. */
- public static final short MESSAGE_TYPE_GAL_F = 0x0602;
+ public static final int TYPE_GAL_F = 0x0602;
/**
* The Navigation Message Status is 'unknown'.
*/
- public static final short STATUS_UNKNOWN = 0;
+ public static final int STATUS_UNKNOWN = 0;
/**
* The Navigation Message was received without any parity error in its navigation words.
*/
- public static final short STATUS_PARITY_PASSED = (1<<0);
+ public static final int STATUS_PARITY_PASSED = (1<<0);
/**
* The Navigation Message was received with words that failed parity check, but the receiver was
* able to correct those words.
*/
- public static final short STATUS_PARITY_REBUILT = (1<<1);
+ public static final int STATUS_PARITY_REBUILT = (1<<1);
// End enumerations in sync with gps.h
- private short mType;
- private short mSvid;
- private short mMessageId;
- private short mSubmessageId;
+ private int mType;
+ private int mSvid;
+ private int mMessageId;
+ private int mSubmessageId;
private byte[] mData;
- private short mStatus;
+ private int mStatus;
GnssNavigationMessage() {
initialize();
@@ -114,14 +113,14 @@
* Gets the type of the navigation message contained in the object.
*/
@GnssNavigationMessageType
- public short getType() {
+ public int getType() {
return mType;
}
/**
* Sets the type of the navigation message.
*/
- public void setType(@GnssNavigationMessageType short value) {
+ public void setType(@GnssNavigationMessageType int value) {
mType = value;
}
@@ -131,25 +130,25 @@
*/
private String getTypeString() {
switch (mType) {
- case MESSAGE_TYPE_UNKNOWN:
+ case TYPE_UNKNOWN:
return "Unknown";
- case MESSAGE_TYPE_GPS_L1CA:
+ case TYPE_GPS_L1CA:
return "GPS L1 C/A";
- case MESSAGE_TYPE_GPS_L2CNAV:
+ case TYPE_GPS_L2CNAV:
return "GPS L2-CNAV";
- case MESSAGE_TYPE_GPS_L5CNAV:
+ case TYPE_GPS_L5CNAV:
return "GPS L5-CNAV";
- case MESSAGE_TYPE_GPS_CNAV2:
+ case TYPE_GPS_CNAV2:
return "GPS CNAV2";
- case MESSAGE_TYPE_GLO_L1CA:
+ case TYPE_GLO_L1CA:
return "Glonass L1 C/A";
- case MESSAGE_TYPE_BDS_D1:
+ case TYPE_BDS_D1:
return "Beidou D1";
- case MESSAGE_TYPE_BDS_D2:
+ case TYPE_BDS_D2:
return "Beidou D2";
- case MESSAGE_TYPE_GAL_I:
+ case TYPE_GAL_I:
return "Galileo I";
- case MESSAGE_TYPE_GAL_F:
+ case TYPE_GAL_F:
return "Galileo F";
default:
return "<Invalid:" + mType + ">";
@@ -160,14 +159,14 @@
* Gets the Pseudo-random number.
* Range: [1, 32].
*/
- public short getSvid() {
+ public int getSvid() {
return mSvid;
}
/**
* Sets the Pseud-random number.
*/
- public void setSvid(short value) {
+ public void setSvid(int value) {
mSvid = value;
}
@@ -177,14 +176,14 @@
* subframe 4 and 5, this value corresponds to the 'frame id' of the navigation message.
* Subframe 1, 2, 3 does not contain a 'frame id' and this might be reported as -1.
*/
- public short getMessageId() {
+ public int getMessageId() {
return mMessageId;
}
/**
* Sets the Message Identifier.
*/
- public void setMessageId(short value) {
+ public void setMessageId(int value) {
mMessageId = value;
}
@@ -194,14 +193,14 @@
* (or frame) that is being transmitted. i.e. for L1 C/A the sub-message identifier corresponds
* to the sub-frame Id of the navigation message.
*/
- public short getSubmessageId() {
+ public int getSubmessageId() {
return mSubmessageId;
}
/**
* Sets the Sub-message identifier.
*/
- public void setSubmessageId(short value) {
+ public void setSubmessageId(int value) {
mSubmessageId = value;
}
@@ -228,14 +227,14 @@
/**
* Gets the Status of the navigation message contained in the object.
*/
- public short getStatus() {
+ public int getStatus() {
return mStatus;
}
/**
* Sets the status of the navigation message.
*/
- public void setStatus(short value) {
+ public void setStatus(int value) {
mStatus = value;
}
@@ -262,10 +261,10 @@
public GnssNavigationMessage createFromParcel(Parcel parcel) {
GnssNavigationMessage navigationMessage = new GnssNavigationMessage();
- navigationMessage.setType((short) parcel.readInt());
- navigationMessage.setSvid((short) parcel.readInt());
- navigationMessage.setMessageId((short) parcel.readInt());
- navigationMessage.setSubmessageId((short) parcel.readInt());
+ navigationMessage.setType(parcel.readInt());
+ navigationMessage.setSvid(parcel.readInt());
+ navigationMessage.setMessageId(parcel.readInt());
+ navigationMessage.setSubmessageId(parcel.readInt());
int dataLength = parcel.readInt();
byte[] data = new byte[dataLength];
@@ -274,7 +273,7 @@
if (parcel.dataAvail() >= Integer.SIZE) {
int status = parcel.readInt();
- navigationMessage.setStatus((short) status);
+ navigationMessage.setStatus(status);
} else {
navigationMessage.setStatus(STATUS_UNKNOWN);
}
@@ -328,7 +327,7 @@
}
private void initialize() {
- mType = MESSAGE_TYPE_UNKNOWN;
+ mType = TYPE_UNKNOWN;
mSvid = 0;
mMessageId = -1;
mSubmessageId = -1;
diff --git a/location/java/android/location/GnssNavigationMessageEvent.java b/location/java/android/location/GnssNavigationMessageEvent.java
index 19c82e9..0df730d 100644
--- a/location/java/android/location/GnssNavigationMessageEvent.java
+++ b/location/java/android/location/GnssNavigationMessageEvent.java
@@ -32,7 +32,7 @@
public final class GnssNavigationMessageEvent implements Parcelable {
/** The status of GPS measurements event. */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GPS_LOCATION_DISABLED})
+ @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GNSS_LOCATION_DISABLED})
public @interface GnssNavigationMessageStatus {}
/**
@@ -50,7 +50,7 @@
/**
* GPS provider or Location is disabled, updated will not be received until they are enabled.
*/
- public static final int STATUS_GPS_LOCATION_DISABLED = 2;
+ public static final int STATUS_GNSS_LOCATION_DISABLED = 2;
private final GnssNavigationMessage mNavigationMessage;
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 06ce30c..2a42fc6 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -27,19 +27,19 @@
*/
public final class GnssStatus {
/** Unknown constellation type. */
- public static final byte CONSTELLATION_UNKNOWN = 0;
+ public static final int CONSTELLATION_UNKNOWN = 0;
/** Constellation type constant for GPS. */
- public static final byte CONSTELLATION_GPS = 1;
+ public static final int CONSTELLATION_GPS = 1;
/** Constellation type constant for SBAS. */
- public static final byte CONSTELLATION_SBAS = 2;
+ public static final int CONSTELLATION_SBAS = 2;
/** Constellation type constant for Glonass. */
- public static final byte CONSTELLATION_GLONASS = 3;
+ public static final int CONSTELLATION_GLONASS = 3;
/** Constellation type constant for QZSS. */
- public static final byte CONSTELLATION_QZSS = 4;
+ public static final int CONSTELLATION_QZSS = 4;
/** Constellation type constant for Beidou. */
- public static final byte CONSTELLATION_BEIDOU = 5;
+ public static final int CONSTELLATION_BEIDOU = 5;
/** Constellation type constant for Galileo. */
- public static final byte CONSTELLATION_GALILEO = 6;
+ public static final int CONSTELLATION_GALILEO = 6;
/** Constellation type. */
@Retention(RetentionPolicy.SOURCE)
@@ -66,16 +66,16 @@
/* These package private values are modified by the LocationManager class */
/* package */ int[] mSvidWithFlags;
- /* package */ float[] mSnrs;
+ /* package */ float[] mCn0DbHz;
/* package */ float[] mElevations;
/* package */ float[] mAzimuths;
/* package */ int mSvCount;
- GnssStatus(int svCount, int[] svidWithFlags, float[] snrs, float[] elevations,
+ GnssStatus(int svCount, int[] svidWithFlags, float[] cn0s, float[] elevations,
float[] azimuths) {
mSvCount = svCount;
mSvidWithFlags = svidWithFlags;
- mSnrs = snrs;
+ mCn0DbHz = cn0s;
mElevations = elevations;
mAzimuths = azimuths;
}
@@ -92,8 +92,8 @@
* @param satIndex the index of the satellite in the list.
*/
@ConstellationType
- public byte getConstellationType(int satIndex) {
- return (byte) ((mSvidWithFlags[satIndex] >> CONSTELLATION_TYPE_SHIFT_WIDTH)
+ public int getConstellationType(int satIndex) {
+ return ((mSvidWithFlags[satIndex] >> CONSTELLATION_TYPE_SHIFT_WIDTH)
& CONSTELLATION_TYPE_MASK);
}
@@ -109,15 +109,15 @@
* Retrieves the signal-noise ration of the satellite at the specified position.
* @param satIndex the index of the satellite in the list.
*/
- public float getSnr(int satIndex) {
- return mSnrs[satIndex];
+ public float getCn0DbHz(int satIndex) {
+ return mCn0DbHz[satIndex];
}
/**
* Retrieves the elevation of the satellite at the specified position.
* @param satIndex the index of the satellite in the list.
*/
- public float getElevation(int satIndex) {
+ public float getElevationDegrees(int satIndex) {
return 0f;
}
@@ -125,7 +125,7 @@
* Retrieves the azimuth the satellite at the specified position.
* @param satIndex the index of the satellite in the list.
*/
- public float getAzimuth(int satIndex) {
+ public float getAzimuthDegrees(int satIndex) {
return mAzimuths[satIndex];
}
diff --git a/location/java/android/location/GnssStatusCallback.java b/location/java/android/location/GnssStatusCallback.java
index b86171b..0d2955a 100644
--- a/location/java/android/location/GnssStatusCallback.java
+++ b/location/java/android/location/GnssStatusCallback.java
@@ -32,13 +32,13 @@
/**
* Called when the GNSS system has received its first fix since starting.
- * @param ttff the time from start to first fix.
+ * @param ttffMillis the time from start to first fix in milliseconds.
*/
- public void onFirstFix(int ttff) {}
+ public void onFirstFix(int ttffMillis) {}
/**
* Called periodically to report GNSS satellite status.
* @param status the current status of all satellites.
*/
public void onSatelliteStatusChanged(GnssStatus status) {}
-}
\ No newline at end of file
+}
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 7b3dd7d..bc518f9 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -138,7 +138,7 @@
// For API-compat a public ctor() is not available
GpsStatus() {}
- private void setStatus(int svCount, int[] svidWithFlags, float[] snrs, float[] elevations,
+ private void setStatus(int svCount, int[] svidWithFlags, float[] cn0s, float[] elevations,
float[] azimuths) {
clearSatellites();
for (int i = 0; i < svCount; i++) {
@@ -158,7 +158,7 @@
}
satellite.mValid = true;
- satellite.mSnr = snrs[i];
+ satellite.mSnr = cn0s[i];
satellite.mElevation = elevations[i];
satellite.mAzimuth = azimuths[i];
satellite.mHasEphemeris =
@@ -179,7 +179,7 @@
*/
void setStatus(GnssStatus status, int timeToFirstFix) {
mTimeToFirstFix = timeToFirstFix;
- setStatus(status.mSvCount, status.mSvidWithFlags, status.mSnrs, status.mElevations,
+ setStatus(status.mSvCount, status.mSvidWithFlags, status.mCn0DbHz, status.mElevations,
status.mAzimuths);
}
diff --git a/location/java/android/location/IGnssStatusListener.aidl b/location/java/android/location/IGnssStatusListener.aidl
index 8c7d06e..d84614f 100644
--- a/location/java/android/location/IGnssStatusListener.aidl
+++ b/location/java/android/location/IGnssStatusListener.aidl
@@ -26,7 +26,7 @@
void onGnssStarted();
void onGnssStopped();
void onFirstFix(int ttff);
- void onSvStatusChanged(int svCount, in int[] svidWithFlags, in float[] snrs,
+ void onSvStatusChanged(int svCount, in int[] svidWithFlags, in float[] cn0s,
in float[] elevations, in float[] azimuths);
void onNmeaReceived(long timestamp, String nmea);
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 3cd47e7..28db099 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1554,9 +1554,9 @@
@Override
public void onSvStatusChanged(int svCount, int[] prnWithFlags,
- float[] snrs, float[] elevations, float[] azimuths) {
+ float[] cn0s, float[] elevations, float[] azimuths) {
if (mGnssCallback != null) {
- mGnssStatus = new GnssStatus(svCount, prnWithFlags, snrs, elevations, azimuths);
+ mGnssStatus = new GnssStatus(svCount, prnWithFlags, cn0s, elevations, azimuths);
Message msg = Message.obtain();
msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
@@ -1805,7 +1805,7 @@
/**
* No-op method to keep backward-compatibility.
- * Don't use it. Use {@link #registerGnssMeasurementCallback} instead.
+ * Don't use it. Use {@link #registerGnssMeasurementsCallback} instead.
* @hide
* @deprecated
*/
@@ -1822,8 +1822,8 @@
* @return {@code true} if the callback was added successfully, {@code false} otherwise.
*/
@RequiresPermission(ACCESS_FINE_LOCATION)
- public boolean registerGnssMeasurementCallback(GnssMeasurementsEvent.Callback callback) {
- return registerGnssMeasurementCallback(callback, null);
+ public boolean registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback) {
+ return registerGnssMeasurementsCallback(callback, null);
}
/**
@@ -1834,14 +1834,14 @@
* @return {@code true} if the callback was added successfully, {@code false} otherwise.
*/
@RequiresPermission(ACCESS_FINE_LOCATION)
- public boolean registerGnssMeasurementCallback(GnssMeasurementsEvent.Callback callback,
+ public boolean registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback,
Handler handler) {
return mGnssMeasurementCallbackTransport.add(callback, handler);
}
/**
* No-op method to keep backward-compatibility.
- * Don't use it. Use {@link #unregisterGnssMeasurementCallback} instead.
+ * Don't use it. Use {@link #unregisterGnssMeasurementsCallback} instead.
* @hide
* @deprecated
*/
@@ -1855,7 +1855,7 @@
*
* @param callback a {@link GnssMeasurementsEvent.Callback} object to remove.
*/
- public void unregisterGnssMeasurementCallback(GnssMeasurementsEvent.Callback callback) {
+ public void unregisterGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback) {
mGnssMeasurementCallbackTransport.remove(callback);
}
diff --git a/location/tests/locationtests/src/android/location/GpsStatusTest.java b/location/tests/locationtests/src/android/location/GpsStatusTest.java
index 4808faf..316e88d 100644
--- a/location/tests/locationtests/src/android/location/GpsStatusTest.java
+++ b/location/tests/locationtests/src/android/location/GpsStatusTest.java
@@ -40,7 +40,7 @@
private GpsStatus mStatus;
private int mCount;
private int[] mPrns;
- private float[] mSnrs;
+ private float[] mCn0s;
private float[] mElevations;
private float[] mAzimuth;
private int mEphemerisMask;
@@ -179,7 +179,7 @@
private void verifySatellites(GpsStatus status) {
verifySatelliteCount(status, mCount);
- verifySatellites(status, mCount, mPrns, mSnrs, mElevations, mAzimuth, mEphemerisMask,
+ verifySatellites(status, mCount, mPrns, mCn0s, mElevations, mAzimuth, mEphemerisMask,
mAlmanacMask, mUsedInFixMask);
}
@@ -187,7 +187,7 @@
GpsStatus status,
int count,
int[] prns,
- float[] snrs,
+ float[] cn0s,
float[] elevations,
float[] azimuth,
int ephemerisMask,
@@ -197,7 +197,7 @@
int prn = prns[i];
GpsSatellite satellite = getSatellite(status, prn);
assertNotNull(getSatelliteAssertInfo(i, prn, "non-null"), satellite);
- assertEquals(getSatelliteAssertInfo(i, prn, "Snr"), snrs[i], satellite.getSnr());
+ assertEquals(getSatelliteAssertInfo(i, prn, "Snr"), cn0s[i], satellite.getSnr());
assertEquals(
getSatelliteAssertInfo(i, prn, "Elevation"),
elevations[i],
@@ -247,7 +247,7 @@
}
private void setSatellites(GpsStatus status) throws Exception {
- set(status, mCount, mPrns, mSnrs, mElevations, mAzimuth, mEphemerisMask, mAlmanacMask,
+ set(status, mCount, mPrns, mCn0s, mElevations, mAzimuth, mEphemerisMask, mAlmanacMask,
mUsedInFixMask);
}
@@ -255,7 +255,7 @@
GpsStatus status,
int count,
int[] prns,
- float[] snrs,
+ float[] cn0s,
float[] elevations,
float[] azimuth,
int ephemerisMask,
@@ -279,7 +279,7 @@
status,
count,
prns,
- snrs,
+ cn0s,
elevations,
azimuth,
ephemerisMask,
@@ -333,7 +333,7 @@
if (!reusePrns) {
mPrns = generateIntArray(count);
}
- mSnrs = generateFloatArray(count);
+ mCn0s = generateFloatArray(count);
mElevations = generateFloatArray(count);
mAzimuth = generateFloatArray(count);
mEphemerisMask = generateMask(mPrns);
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c7e96cf..8206d23 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2147,9 +2147,10 @@
}
break;
case MSSG_RECORDING_CONFIG_CHANGE:
- final AudioRecordingCallback cb = (AudioRecordingCallback) msg.obj;
- if (cb != null) {
- cb.onRecordConfigChanged();
+ final RecordConfigChangeCallbackData cbData =
+ (RecordConfigChangeCallbackData) msg.obj;
+ if (cbData.mCb != null) {
+ cbData.mCb.onRecordConfigChanged(cbData.mConfigs);
}
break;
default:
@@ -2734,8 +2735,10 @@
public static abstract class AudioRecordingCallback {
/**
* Called whenever the device recording configuration has changed.
+ * @param configs array containing the results of
+ * {@link AudioManager#getActiveRecordConfigurations()}.
*/
- public void onRecordConfigChanged() {}
+ public void onRecordConfigChanged(AudioRecordConfiguration[] configs) {}
}
private static class AudioRecordingCallbackInfo {
@@ -2747,6 +2750,17 @@
}
}
+ private final static class RecordConfigChangeCallbackData {
+ final AudioRecordingCallback mCb;
+ final AudioRecordConfiguration[] mConfigs;
+
+ RecordConfigChangeCallbackData(AudioRecordingCallback cb,
+ AudioRecordConfiguration[] configs) {
+ mCb = cb;
+ mConfigs = configs;
+ }
+ }
+
/**
* Register a callback to be notified of audio recording changes through
* {@link AudioRecordingCallback}
@@ -2882,14 +2896,15 @@
private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
- public void dispatchRecordingConfigChange() {
+ public void dispatchRecordingConfigChange(AudioRecordConfiguration[] configs) {
synchronized(mRecordCallbackLock) {
if (mRecordCallbackList != null) {
for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i);
if (arci.mHandler != null) {
final Message m = arci.mHandler.obtainMessage(
- MSSG_RECORDING_CONFIG_CHANGE/*what*/, arci.mCb/*obj*/);
+ MSSG_RECORDING_CONFIG_CHANGE/*what*/,
+ new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
arci.mHandler.sendMessage(m);
}
}
diff --git a/media/java/android/media/AudioRecordConfiguration.java b/media/java/android/media/AudioRecordConfiguration.java
index 2fc8ee8..de78a5a 100644
--- a/media/java/android/media/AudioRecordConfiguration.java
+++ b/media/java/android/media/AudioRecordConfiguration.java
@@ -16,10 +16,13 @@
package android.media;
+import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Objects;
@@ -53,6 +56,19 @@
mPatchHandle = patchHandle;
}
+ /** @hide */
+ @IntDef({
+ MediaRecorder.AudioSource.DEFAULT,
+ MediaRecorder.AudioSource.VOICE_UPLINK,
+ MediaRecorder.AudioSource.VOICE_DOWNLINK,
+ MediaRecorder.AudioSource.VOICE_CALL,
+ MediaRecorder.AudioSource.CAMCORDER,
+ MediaRecorder.AudioSource.VOICE_RECOGNITION,
+ MediaRecorder.AudioSource.VOICE_COMMUNICATION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AudioSource {}
+
/**
* Returns the audio source being used for the recording.
* @return one of {@link MediaRecorder.AudioSource#MIC},
@@ -63,7 +79,7 @@
* {@link MediaRecorder.AudioSource#VOICE_RECOGNITION},
* {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}.
*/
- public int getClientAudioSource() { return mClientSource; }
+ public @AudioSource int getClientAudioSource() { return mClientSource; }
/**
* Returns the session number of the recording, see {@link AudioRecord#getAudioSessionId()}.
diff --git a/media/java/android/media/IRecordingConfigDispatcher.aidl b/media/java/android/media/IRecordingConfigDispatcher.aidl
index a5eb8b9f..eaa92ca 100644
--- a/media/java/android/media/IRecordingConfigDispatcher.aidl
+++ b/media/java/android/media/IRecordingConfigDispatcher.aidl
@@ -16,6 +16,8 @@
package android.media;
+import android.media.AudioRecordConfiguration;
+
/**
* AIDL for the RecordingActivity monitor in AudioService to signal audio recording updates.
*
@@ -23,6 +25,6 @@
*/
oneway interface IRecordingConfigDispatcher {
- void dispatchRecordingConfigChange();
+ void dispatchRecordingConfigChange(in AudioRecordConfiguration[] configs);
}
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 646ab4e..a0e2481 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -644,6 +644,21 @@
/** Full range. Y, Cr and Cb component values range from 0 to 255 for 8-bit content. */
public static final int COLOR_RANGE_FULL = 1;
+ /**
+ * A key describing a unique ID for the content of a media track.
+ *
+ * <p>This key is used by {@link MediaExtractor}. Some extractors provide multiple encodings
+ * of the same track (e.g. float audio tracks for FLAC and WAV may be expressed as two
+ * tracks via MediaExtractor: a normal PCM track for backward compatibility, and a float PCM
+ * track for added fidelity. Similarly, Dolby Vision extractor may provide a baseline SDR
+ * version of a DV track.) This key can be used to identify which MediaExtractor tracks refer
+ * to the same underlying content.
+ * </p>
+ *
+ * The associated value is an integer.
+ */
+ public static final String KEY_TRACK_ID = "track-id";
+
/* package private */ MediaFormat(Map<String, Object> map) {
mMap = map;
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index adf8551..b78869e 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -2845,13 +2845,17 @@
MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
sendMessage(msg2);
}
- if (mOnPreparedListener != null)
- mOnPreparedListener.onPrepared(mMediaPlayer);
+ OnPreparedListener onPreparedListener = mOnPreparedListener;
+ if (onPreparedListener != null)
+ onPreparedListener.onPrepared(mMediaPlayer);
return;
case MEDIA_PLAYBACK_COMPLETE:
- if (mOnCompletionListener != null)
- mOnCompletionListener.onCompletion(mMediaPlayer);
+ {
+ OnCompletionListener onCompletionListener = mOnCompletionListener;
+ if (onCompletionListener != null)
+ onCompletionListener.onCompletion(mMediaPlayer);
+ }
stayAwake(false);
return;
@@ -2875,13 +2879,15 @@
break;
case MEDIA_BUFFERING_UPDATE:
- if (mOnBufferingUpdateListener != null)
- mOnBufferingUpdateListener.onBufferingUpdate(mMediaPlayer, msg.arg1);
+ OnBufferingUpdateListener onBufferingUpdateListener = mOnBufferingUpdateListener;
+ if (onBufferingUpdateListener != null)
+ onBufferingUpdateListener.onBufferingUpdate(mMediaPlayer, msg.arg1);
return;
case MEDIA_SEEK_COMPLETE:
- if (mOnSeekCompleteListener != null) {
- mOnSeekCompleteListener.onSeekComplete(mMediaPlayer);
+ OnSeekCompleteListener onSeekCompleteListener = mOnSeekCompleteListener;
+ if (onSeekCompleteListener != null) {
+ onSeekCompleteListener.onSeekComplete(mMediaPlayer);
}
// fall through
@@ -2895,8 +2901,9 @@
return;
case MEDIA_SET_VIDEO_SIZE:
- if (mOnVideoSizeChangedListener != null) {
- mOnVideoSizeChangedListener.onVideoSizeChanged(
+ OnVideoSizeChangedListener onVideoSizeChangedListener = mOnVideoSizeChangedListener;
+ if (onVideoSizeChangedListener != null) {
+ onVideoSizeChangedListener.onVideoSizeChanged(
mMediaPlayer, msg.arg1, msg.arg2);
}
return;
@@ -2904,11 +2911,15 @@
case MEDIA_ERROR:
Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
boolean error_was_handled = false;
- if (mOnErrorListener != null) {
- error_was_handled = mOnErrorListener.onError(mMediaPlayer, msg.arg1, msg.arg2);
+ OnErrorListener onErrorListener = mOnErrorListener;
+ if (onErrorListener != null) {
+ error_was_handled = onErrorListener.onError(mMediaPlayer, msg.arg1, msg.arg2);
}
- if (mOnCompletionListener != null && ! error_was_handled) {
- mOnCompletionListener.onCompletion(mMediaPlayer);
+ {
+ OnCompletionListener onCompletionListener = mOnCompletionListener;
+ if (onCompletionListener != null && ! error_was_handled) {
+ onCompletionListener.onCompletion(mMediaPlayer);
+ }
}
stayAwake(false);
return;
@@ -2944,47 +2955,52 @@
break;
}
- if (mOnInfoListener != null) {
- mOnInfoListener.onInfo(mMediaPlayer, msg.arg1, msg.arg2);
+ OnInfoListener onInfoListener = mOnInfoListener;
+ if (onInfoListener != null) {
+ onInfoListener.onInfo(mMediaPlayer, msg.arg1, msg.arg2);
}
// No real default action so far.
return;
case MEDIA_TIMED_TEXT:
- if (mOnTimedTextListener == null)
+ OnTimedTextListener onTimedTextListener = mOnTimedTextListener;
+ if (onTimedTextListener == null)
return;
if (msg.obj == null) {
- mOnTimedTextListener.onTimedText(mMediaPlayer, null);
+ onTimedTextListener.onTimedText(mMediaPlayer, null);
} else {
if (msg.obj instanceof Parcel) {
Parcel parcel = (Parcel)msg.obj;
TimedText text = new TimedText(parcel);
parcel.recycle();
- mOnTimedTextListener.onTimedText(mMediaPlayer, text);
+ onTimedTextListener.onTimedText(mMediaPlayer, text);
}
}
return;
case MEDIA_SUBTITLE_DATA:
- if (mOnSubtitleDataListener == null) {
+ OnSubtitleDataListener onSubtitleDataListener = mOnSubtitleDataListener;
+ if (onSubtitleDataListener == null) {
return;
}
if (msg.obj instanceof Parcel) {
Parcel parcel = (Parcel) msg.obj;
SubtitleData data = new SubtitleData(parcel);
parcel.recycle();
- mOnSubtitleDataListener.onSubtitleData(mMediaPlayer, data);
+ onSubtitleDataListener.onSubtitleData(mMediaPlayer, data);
}
return;
case MEDIA_META_DATA:
- if (mOnTimedMetaDataAvailableListener == null) {
+ OnTimedMetaDataAvailableListener onTimedMetaDataAvailableListener =
+ mOnTimedMetaDataAvailableListener;
+ if (onTimedMetaDataAvailableListener == null) {
return;
}
if (msg.obj instanceof Parcel) {
Parcel parcel = (Parcel) msg.obj;
TimedMetaData data = TimedMetaData.createTimedMetaDataFromParcel(parcel);
parcel.recycle();
- mOnTimedMetaDataAvailableListener.onTimedMetaDataAvailable(mMediaPlayer, data);
+ onTimedMetaDataAvailableListener.onTimedMetaDataAvailable(mMediaPlayer, data);
}
return;
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index b5ea2a0..f593685 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -370,15 +370,14 @@
* called when the loading is complete.
* </p><p>
* In case the media item does not have any children, call {@link Result#sendResult}
- * with an empty list which is not {@code null}. If {@code null} is sent that means
- * the given {@code parentId} is invalid and {@link MediaBrowser.SubscriptionCallback#onError}
- * will be called.
+ * with an empty list. When the given {@code parentId} is invalid, implementations must
+ * call {@link Result#sendResult result.sendResult} with {@code null}, which will invoke
+ * {@link MediaBrowser.SubscriptionCallback#onError}.
* </p>
*
* @param parentId The id of the parent media item whose children are to be
* queried.
- * @param result The Result to send the list of children to. Send null if the
- * id is invalid.
+ * @param result The Result to send the list of children to.
*/
public abstract void onLoadChildren(@NonNull String parentId,
@NonNull Result<List<MediaBrowser.MediaItem>> result);
@@ -394,15 +393,14 @@
* called when the loading is complete.
* </p><p>
* In case the media item does not have any children, call {@link Result#sendResult}
- * with an empty list which is not {@code null}. If {@code null} is sent that means
- * the given {@code parentId} is invalid and {@link MediaBrowser.SubscriptionCallback#onError}
- * will be called.
+ * with an empty list. When the given {@code parentId} is invalid, implementations must
+ * call {@link Result#sendResult result.sendResult} with {@code null}, which will invoke
+ * {@link MediaBrowser.SubscriptionCallback#onError}.
* </p>
*
* @param parentId The id of the parent media item whose children are to be
* queried.
- * @param result The Result to send the list of children to. Send null if the
- * id is invalid.
+ * @param result The Result to send the list of children to.
* @param options A bundle of service-specific arguments sent from the media
* browse. The information returned through the result should be
* affected by the contents of this bundle.
@@ -424,13 +422,18 @@
* result.detach} may be called before returning from this function, and
* then {@link Result#sendResult result.sendResult} called when the item has
* been loaded.
- * <p>
- * The default implementation sends a null result.
+ * </p><p>
+ * When the given {@code itemId} is invalid, implementations must call
+ * {@link Result#sendResult result.sendResult} with {@code null}, which will
+ * invoke {@link MediaBrowser.ItemCallback#onError}.
+ * </p><p>
+ * The default implementation calls {@link Result#sendResult result.sendResult}
+ * with {@code null}.
+ * </p>
*
* @param itemId The id for the specific
* {@link android.media.browse.MediaBrowser.MediaItem}.
- * @param result The Result to send the item to. Send null if the id is
- * invalid.
+ * @param result The Result to send the item to.
*/
public void onLoadItem(String itemId, Result<MediaBrowser.MediaItem> result) {
result.sendResult(null);
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index fa9c48c..29739ca 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -64,7 +64,6 @@
frameworks/av/media/mtp \
frameworks/native/include/media/openmax \
$(call include-path-for, libhardware)/hardware \
- system/media/camera/include \
$(PV_INCLUDES) \
$(JNI_H_INCLUDE)
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 2004a3a..d6994b3 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -1302,7 +1302,10 @@
jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
CryptoPlugin::Pattern pattern;
- if (patternObj != NULL) {
+ if (patternObj == NULL) {
+ pattern.mEncryptBlocks = 0;
+ pattern.mSkipBlocks = 0;
+ } else {
pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
}
diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp
index 3b892cb..537b56d 100644
--- a/media/jni/android_media_MediaDataSource.cpp
+++ b/media/jni/android_media_MediaDataSource.cpp
@@ -116,7 +116,8 @@
return UNKNOWN_ERROR;
}
if (mSizeIsCached) {
- return mCachedSize;
+ *size = mCachedSize;
+ return OK;
}
JNIEnv* env = AndroidRuntime::getJNIEnv();
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 701f7ac..922ad79 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -26,7 +26,6 @@
#include <utils/Log.h>
#include <gui/Surface.h>
-#include <camera/ICameraService.h>
#include <camera/Camera.h>
#include <media/mediarecorder.h>
#include <media/stagefright/PersistentSurface.h>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
index 61dede3..9be7004 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
@@ -60,10 +60,7 @@
}
private void addCameraUnitTests(TestSuite suite) {
- suite.addTestSuite(CameraUtilsDecoratorTest.class);
- suite.addTestSuite(CameraUtilsRuntimeExceptionTest.class);
suite.addTestSuite(CameraUtilsUncheckedThrowTest.class);
- suite.addTestSuite(CameraUtilsBinderDecoratorTest.class);
suite.addTestSuite(CameraUtilsTypeReferenceTest.class);
suite.addTestSuite(CameraMetadataTest.class);
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 6f74203..9a0946e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -19,16 +19,16 @@
import android.hardware.CameraInfo;
import android.hardware.ICamera;
import android.hardware.ICameraClient;
+import android.hardware.ICameraService;
import android.hardware.ICameraServiceListener;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.impl.CaptureResultExtras;
-import android.hardware.camera2.utils.BinderHolder;
-import android.hardware.camera2.utils.CameraBinderDecorator;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
@@ -84,14 +84,7 @@
public void testCameraInfo() throws Exception {
for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
- CameraInfo info = new CameraInfo();
- info.info.facing = -1;
- info.info.orientation = -1;
-
- assertTrue(
- "Camera service returned info for camera " + cameraId,
- mUtils.getCameraService().getCameraInfo(cameraId, info) ==
- CameraBinderTestUtils.NO_ERROR);
+ CameraInfo info = mUtils.getCameraService().getCameraInfo(cameraId);
assertTrue("Facing was not set for camera " + cameraId, info.info.facing != -1);
assertTrue("Orientation was not set for camera " + cameraId,
info.info.orientation != -1);
@@ -105,20 +98,17 @@
public void testGetLegacyParameters() throws Exception {
for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
- String[] parameters = new String[1];
- assertEquals("Camera service returned parameters for camera " + cameraId,
- CameraBinderTestUtils.NO_ERROR,
- mUtils.getCameraService().getLegacyParameters(cameraId, /*out*/parameters));
- assertNotNull(parameters[0]);
+ String parameters = mUtils.getCameraService().getLegacyParameters(cameraId);
+ assertNotNull(parameters);
assertTrue("Parameters should have at least one character in it",
- parameters[0].length() > 0);
+ parameters.length() > 0);
- int end = parameters[0].length();
+ int end = parameters.length();
if (end > MAX_PARAMETERS_LENGTH) {
end = MAX_PARAMETERS_LENGTH;
}
- Log.v(TAG, "Camera " + cameraId + " parameters: " + parameters[0].substring(0, end));
+ Log.v(TAG, "Camera " + cameraId + " parameters: " + parameters.substring(0, end));
}
}
@@ -127,14 +117,8 @@
public void testSupportsCamera2Api() throws Exception {
for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
- int res = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_2);
+ boolean supports = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_2);
- if (res != CameraBinderTestUtils.NO_ERROR && res != -android.system.OsConstants.EOPNOTSUPP) {
- fail("Camera service returned bad value when queried if it supports camera2 api: "
- + res + " for camera ID " + cameraId);
- }
-
- boolean supports = res == CameraBinderTestUtils.NO_ERROR;
Log.v(TAG, "Camera " + cameraId + " supports api2: " + supports);
}
}
@@ -144,10 +128,10 @@
public void testSupportsCamera1Api() throws Exception {
for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
- int res = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_1);
- assertEquals(
- "Camera service returned bad value when queried if it supports camera1 api: "
- + res + " for camera ID " + cameraId, CameraBinderTestUtils.NO_ERROR, res);
+ boolean supports = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_1);
+ assertTrue(
+ "Camera service returned false when queried if it supports camera1 api " +
+ " for camera ID " + cameraId, supports);
}
}
@@ -169,11 +153,10 @@
String clientPackageName = getContext().getPackageName();
- BinderHolder holder = new BinderHolder();
- CameraBinderDecorator.newInstance(mUtils.getCameraService())
+ ICamera cameraUser = mUtils.getCameraService()
.connect(dummyCallbacks, cameraId, clientPackageName,
- CameraBinderTestUtils.USE_CALLING_UID, holder);
- ICamera cameraUser = ICamera.Stub.asInterface(holder.getBinder());
+ ICameraService.USE_CALLING_UID,
+ ICameraService.USE_CALLING_PID);
assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
Log.v(TAG, String.format("Camera %s connected", cameraId));
@@ -191,14 +174,11 @@
String clientPackageName = getContext().getPackageName();
- BinderHolder holder = new BinderHolder();
-
try {
- CameraBinderDecorator.newInstance(mUtils.getCameraService())
+ cameraUser = mUtils.getCameraService()
.connectLegacy(dummyCallbacks, cameraId, CAMERA_HAL_API_VERSION_1_0,
- clientPackageName,
- CameraBinderTestUtils.USE_CALLING_UID, holder);
- cameraUser = ICamera.Stub.asInterface(holder.getBinder());
+ clientPackageName,
+ ICameraService.USE_CALLING_UID);
assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
Log.v(TAG, String.format("Camera %s connected as HAL1 legacy device", cameraId));
@@ -284,11 +264,11 @@
String clientPackageName = getContext().getPackageName();
- BinderHolder holder = new BinderHolder();
- CameraBinderDecorator.newInstance(mUtils.getCameraService())
- .connectDevice(dummyCallbacks, cameraId,
- clientPackageName, CameraBinderTestUtils.USE_CALLING_UID, holder);
- ICameraDeviceUser cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
+ ICameraDeviceUser cameraUser =
+ mUtils.getCameraService().connectDevice(
+ dummyCallbacks, cameraId,
+ clientPackageName,
+ ICameraService.USE_CALLING_UID);
assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
Log.v(TAG, String.format("Camera %s connected", cameraId));
@@ -323,27 +303,33 @@
ICameraServiceListener listener = new DummyCameraServiceListener();
- assertTrue(
- "Listener was removed before added",
- mUtils.getCameraService().removeListener(listener) ==
- CameraBinderTestUtils.BAD_VALUE);
+ try {
+ mUtils.getCameraService().removeListener(listener);
+ fail("Listener was removed before added");
+ } catch (ServiceSpecificException e) {
+ assertEquals("Listener was removed before added",
+ e.errorCode, ICameraService.ERROR_ILLEGAL_ARGUMENT);
+ }
- assertTrue("Listener was not added",
- mUtils.getCameraService().addListener(listener) ==
- CameraBinderTestUtils.NO_ERROR);
- assertTrue(
- "Listener was wrongly added again",
- mUtils.getCameraService().addListener(listener) ==
- CameraBinderTestUtils.ALREADY_EXISTS);
+ mUtils.getCameraService().addListener(listener);
- assertTrue(
- "Listener was not removed",
- mUtils.getCameraService().removeListener(listener) ==
- CameraBinderTestUtils.NO_ERROR);
- assertTrue(
- "Listener was wrongly removed again",
- mUtils.getCameraService().removeListener(listener) ==
- CameraBinderTestUtils.BAD_VALUE);
+ try {
+ mUtils.getCameraService().addListener(listener);
+ fail("Listener was wrongly added again");
+ } catch (ServiceSpecificException e) {
+ assertEquals("Listener was wrongly added again",
+ e.errorCode, ICameraService.ERROR_ALREADY_EXISTS);
+ }
+
+ mUtils.getCameraService().removeListener(listener);
+
+ try {
+ mUtils.getCameraService().removeListener(listener);
+ fail("Listener was wrongly removed twice");
+ } catch (ServiceSpecificException e) {
+ assertEquals("Listener was wrongly removed twice",
+ e.errorCode, ICameraService.ERROR_ILLEGAL_ARGUMENT);
+ }
}
}
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
index 5c4b23b..38fc49f 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
@@ -18,10 +18,6 @@
static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
- protected static final int USE_CALLING_UID = -1;
- protected static final int BAD_VALUE = -EINVAL;
- protected static final int INVALID_OPERATION = -ENOSYS;
- protected static final int ALREADY_EXISTS = -EEXIST;
public static final int NO_ERROR = 0;
private final Context mContext;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index d71b44b..5c1d8a7 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -18,6 +18,7 @@
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
+import android.hardware.ICameraService;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
@@ -27,12 +28,13 @@
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.impl.CaptureResultExtras;
import android.hardware.camera2.params.OutputConfiguration;
-import android.hardware.camera2.utils.BinderHolder;
+import android.hardware.camera2.utils.SubmitInfo;
import android.media.Image;
import android.media.ImageReader;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
@@ -164,11 +166,10 @@
}
private CaptureRequest.Builder createDefaultBuilder(boolean needStream) throws Exception {
- CameraMetadataNative metadata = new CameraMetadataNative();
+ CameraMetadataNative metadata = null;
assertTrue(metadata.isEmpty());
- int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata);
- assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+ metadata = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW);
assertFalse(metadata.isEmpty());
CaptureRequest.Builder request = new CaptureRequest.Builder(metadata, /*reprocess*/false,
@@ -183,12 +184,13 @@
return request;
}
- private int submitCameraRequest(CaptureRequest request, boolean streaming) throws Exception {
- int requestId = mCameraUser.submitRequest(request, streaming, null);
+ private SubmitInfo submitCameraRequest(CaptureRequest request, boolean streaming) throws Exception {
+ SubmitInfo requestInfo = mCameraUser.submitRequest(request, streaming);
assertTrue(
- "Request IDs should be non-negative (expected: >= 0, actual: " + requestId + ")",
- requestId >= 0);
- return requestId;
+ "Request IDs should be non-negative (expected: >= 0, actual: " +
+ requestInfo.getRequestId() + ")",
+ requestInfo.getRequestId() >= 0);
+ return requestInfo;
}
@Override
@@ -214,10 +216,8 @@
mMockCb = spy(dummyCallbacks);
- BinderHolder holder = new BinderHolder();
- mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
- clientPackageName, CameraBinderTestUtils.USE_CALLING_UID, holder);
- mCameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
+ mCameraUser = mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
+ clientPackageName, ICameraService.USE_CALLING_UID);
assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser);
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
@@ -238,11 +238,10 @@
@SmallTest
public void testCreateDefaultRequest() throws Exception {
- CameraMetadataNative metadata = new CameraMetadataNative();
+ CameraMetadataNative metadata = null;
assertTrue(metadata.isEmpty());
- int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata);
- assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+ metadata = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW);
assertFalse(metadata.isEmpty());
}
@@ -252,18 +251,28 @@
int streamId = mCameraUser.createStream(mOutputConfiguration);
assertEquals(0, streamId);
- assertEquals(CameraBinderTestUtils.ALREADY_EXISTS,
- mCameraUser.createStream(mOutputConfiguration));
+ try {
+ mCameraUser.createStream(mOutputConfiguration);
+ fail("Creating same stream twice");
+ } catch (ServiceSpecificException e) {
+ assertEquals("Creating same stream twice",
+ e.errorCode, ICameraService.ERROR_ALREADY_EXISTS);
+ }
- assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId));
+ mCameraUser.deleteStream(streamId);
}
@SmallTest
public void testDeleteInvalidStream() throws Exception {
- assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(-1));
- assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(0));
- assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(1));
- assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(0xC0FFEE));
+ int[] badStreams = { -1, 0, 1, 0xC0FFEE };
+ for (int badStream : badStreams) {
+ try {
+ mCameraUser.deleteStream(badStream);
+ fail("Allowed bad stream delete");
+ } catch (ServiceSpecificException e) {
+ assertEquals(e.errorCode, ICameraService.ERROR_ILLEGAL_ARGUMENT);
+ }
+ }
}
@SmallTest
@@ -273,8 +282,13 @@
int streamId = mCameraUser.createStream(mOutputConfiguration);
assertEquals(0, streamId);
- assertEquals(CameraBinderTestUtils.ALREADY_EXISTS,
- mCameraUser.createStream(mOutputConfiguration));
+ try {
+ mCameraUser.createStream(mOutputConfiguration);
+ fail("Created same stream twice");
+ } catch (ServiceSpecificException e) {
+ assertEquals("Created same stream twice",
+ ICameraService.ERROR_ALREADY_EXISTS, e.errorCode);
+ }
// Create second stream with a different surface.
SurfaceTexture surfaceTexture = new SurfaceTexture(/* ignored */0);
@@ -286,8 +300,8 @@
assertEquals(1, streamId2);
// Clean up streams
- assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId));
- assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId2));
+ mCameraUser.deleteStream(streamId);
+ mCameraUser.deleteStream(streamId2);
}
@SmallTest
@@ -295,16 +309,25 @@
CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */false);
CaptureRequest request1 = builder.build();
- int status = mCameraUser.submitRequest(request1, /* streaming */false, null);
- assertEquals("Expected submitRequest to return BAD_VALUE " +
- "since we had 0 surface targets set.", CameraBinderTestUtils.BAD_VALUE, status);
+ try {
+ SubmitInfo requestInfo = mCameraUser.submitRequest(request1, /* streaming */false);
+ fail("Exception expected");
+ } catch(ServiceSpecificException e) {
+ assertEquals("Expected submitRequest to throw ServiceSpecificException with BAD_VALUE " +
+ "since we had 0 surface targets set.", ICameraService.ERROR_ILLEGAL_ARGUMENT,
+ e.errorCode);
+ }
builder.addTarget(mSurface);
CaptureRequest request2 = builder.build();
- status = mCameraUser.submitRequest(request2, /* streaming */false, null);
- assertEquals("Expected submitRequest to return BAD_VALUE since " +
- "the target surface wasn't registered with createStream.",
- CameraBinderTestUtils.BAD_VALUE, status);
+ try {
+ SubmitInfo requestInfo = mCameraUser.submitRequest(request2, /* streaming */false);
+ fail("Exception expected");
+ } catch(ServiceSpecificException e) {
+ assertEquals("Expected submitRequest to throw ILLEGAL_ARGUMENT " +
+ "ServiceSpecificException since the target wasn't registered with createStream.",
+ ICameraService.ERROR_ILLEGAL_ARGUMENT, e.errorCode);
+ }
}
@SmallTest
@@ -314,9 +337,10 @@
CaptureRequest request = builder.build();
// Submit valid request twice.
- int requestId1 = submitCameraRequest(request, /* streaming */false);
- int requestId2 = submitCameraRequest(request, /* streaming */false);
- assertNotSame("Request IDs should be unique for multiple requests", requestId1, requestId2);
+ SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
+ SubmitInfo requestInfo2 = submitCameraRequest(request, /* streaming */false);
+ assertNotSame("Request IDs should be unique for multiple requests",
+ requestInfo1.getRequestId(), requestInfo2.getRequestId());
}
@@ -329,32 +353,35 @@
// Submit valid request once (non-streaming), and another time
// (streaming)
- int requestId1 = submitCameraRequest(request, /* streaming */false);
+ SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
- int requestIdStreaming = submitCameraRequest(request, /* streaming */true);
- assertNotSame("Request IDs should be unique for multiple requests", requestId1,
- requestIdStreaming);
+ SubmitInfo requestInfoStreaming = submitCameraRequest(request, /* streaming */true);
+ assertNotSame("Request IDs should be unique for multiple requests",
+ requestInfo1.getRequestId(),
+ requestInfoStreaming.getRequestId());
- int status = mCameraUser.cancelRequest(-1, null);
- assertEquals("Invalid request IDs should not be cancellable",
- CameraBinderTestUtils.BAD_VALUE, status);
+ try {
+ long lastFrameNumber = mCameraUser.cancelRequest(-1);
+ fail("Expected exception");
+ } catch (ServiceSpecificException e) {
+ assertEquals("Invalid request IDs should not be cancellable",
+ ICameraService.ERROR_ILLEGAL_ARGUMENT, e.errorCode);
+ }
- status = mCameraUser.cancelRequest(requestId1, null);
- assertEquals("Non-streaming request IDs should not be cancellable",
- CameraBinderTestUtils.BAD_VALUE, status);
+ try {
+ long lastFrameNumber = mCameraUser.cancelRequest(requestInfo1.getRequestId());
+ fail("Expected exception");
+ } catch (ServiceSpecificException e) {
+ assertEquals("Non-streaming request IDs should not be cancellable",
+ ICameraService.ERROR_ILLEGAL_ARGUMENT, e.errorCode);
+ }
- status = mCameraUser.cancelRequest(requestIdStreaming, null);
- assertEquals("Streaming request IDs should be cancellable", CameraBinderTestUtils.NO_ERROR,
- status);
-
+ long lastFrameNumber = mCameraUser.cancelRequest(requestInfoStreaming.getRequestId());
}
@SmallTest
public void testCameraInfo() throws RemoteException {
- CameraMetadataNative info = new CameraMetadataNative();
-
- int status = mCameraUser.getCameraInfo(/*out*/info);
- assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+ CameraMetadataNative info = mCameraUser.getCameraInfo();
assertFalse(info.isEmpty());
assertNotNull(info.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS));
@@ -362,10 +389,7 @@
@SmallTest
public void testCameraCharacteristics() throws RemoteException {
- CameraMetadataNative info = new CameraMetadataNative();
-
- int status = mUtils.getCameraService().getCameraCharacteristics(mCameraId, /*out*/info);
- assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+ CameraMetadataNative info = mUtils.getCameraService().getCameraCharacteristics(mCameraId);
assertFalse(info.isEmpty());
assertNotNull(info.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS));
@@ -374,18 +398,19 @@
@SmallTest
public void testWaitUntilIdle() throws Exception {
CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true);
- int requestIdStreaming = submitCameraRequest(builder.build(), /* streaming */true);
+ SubmitInfo requestInfoStreaming = submitCameraRequest(builder.build(), /* streaming */true);
// Test Bad case first: waitUntilIdle when there is active repeating request
- int status = mCameraUser.waitUntilIdle();
- assertEquals("waitUntilIdle is invalid operation when there is active repeating request",
- CameraBinderTestUtils.INVALID_OPERATION, status);
+ try {
+ mCameraUser.waitUntilIdle();
+ } catch (ServiceSpecificException e) {
+ assertEquals("waitUntilIdle is invalid operation when there is active repeating request",
+ ICameraService.ERROR_INVALID_OPERATION, e.errorCode);
+ }
// Test good case, waitUntilIdle when there is no active repeating request
- status = mCameraUser.cancelRequest(requestIdStreaming, null);
- assertEquals(CameraBinderTestUtils.NO_ERROR, status);
- status = mCameraUser.waitUntilIdle();
- assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+ long lastFrameNumber = mCameraUser.cancelRequest(requestInfoStreaming.getRequestId());
+ mCameraUser.waitUntilIdle();
}
@SmallTest
@@ -411,12 +436,12 @@
ArgumentCaptor<Long> timestamps = ArgumentCaptor.forClass(Long.class);
// Test both single request and streaming request.
- int requestId1 = submitCameraRequest(request, /* streaming */false);
+ SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).times(1)).onCaptureStarted(
any(CaptureResultExtras.class),
anyLong());
- int streamingId = submitCameraRequest(request, /* streaming */true);
+ SubmitInfo streamingInfo = submitCameraRequest(request, /* streaming */true);
verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).atLeast(NUM_CALLBACKS_CHECKED))
.onCaptureStarted(
any(CaptureResultExtras.class),
@@ -436,22 +461,22 @@
CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
// Try streaming
- int streamingId = submitCameraRequest(request, /* streaming */true);
+ SubmitInfo streamingInfo = submitCameraRequest(request, /* streaming */true);
// Wait a bit to fill up the queue
SystemClock.sleep(WAIT_FOR_WORK_MS);
// Cancel and make sure we eventually quiesce
- status = mCameraUser.cancelRequest(streamingId, null);
+ long lastFrameNumber = mCameraUser.cancelRequest(streamingInfo.getRequestId());
verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(1)).onDeviceIdle();
// Submit a few capture requests
- int requestId1 = submitCameraRequest(request, /* streaming */false);
- int requestId2 = submitCameraRequest(request, /* streaming */false);
- int requestId3 = submitCameraRequest(request, /* streaming */false);
- int requestId4 = submitCameraRequest(request, /* streaming */false);
- int requestId5 = submitCameraRequest(request, /* streaming */false);
+ SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
+ SubmitInfo requestInfo2 = submitCameraRequest(request, /* streaming */false);
+ SubmitInfo requestInfo3 = submitCameraRequest(request, /* streaming */false);
+ SubmitInfo requestInfo4 = submitCameraRequest(request, /* streaming */false);
+ SubmitInfo requestInfo5 = submitCameraRequest(request, /* streaming */false);
// And wait for more idle
verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(2)).onDeviceIdle();
@@ -463,38 +488,34 @@
int status;
// Initial flush should work
- status = mCameraUser.flush(null);
- assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+ long lastFrameNumber = mCameraUser.flush();
// Then set up a stream
CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
// Flush should still be a no-op, really
- status = mCameraUser.flush(null);
- assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+ lastFrameNumber = mCameraUser.flush();
// Submit a few capture requests
- int requestId1 = submitCameraRequest(request, /* streaming */false);
- int requestId2 = submitCameraRequest(request, /* streaming */false);
- int requestId3 = submitCameraRequest(request, /* streaming */false);
- int requestId4 = submitCameraRequest(request, /* streaming */false);
- int requestId5 = submitCameraRequest(request, /* streaming */false);
+ SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
+ SubmitInfo requestInfo2 = submitCameraRequest(request, /* streaming */false);
+ SubmitInfo requestInfo3 = submitCameraRequest(request, /* streaming */false);
+ SubmitInfo requestInfo4 = submitCameraRequest(request, /* streaming */false);
+ SubmitInfo requestInfo5 = submitCameraRequest(request, /* streaming */false);
// Then flush and wait for idle
- status = mCameraUser.flush(null);
- assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+ lastFrameNumber = mCameraUser.flush();
verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(1)).onDeviceIdle();
// Now a streaming request
- int streamingId = submitCameraRequest(request, /* streaming */true);
+ SubmitInfo streamingInfo = submitCameraRequest(request, /* streaming */true);
// Wait a bit to fill up the queue
SystemClock.sleep(WAIT_FOR_WORK_MS);
// Then flush and wait for the idle callback
- status = mCameraUser.flush(null);
- assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+ lastFrameNumber = mCameraUser.flush();
verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(2)).onDeviceIdle();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java
deleted file mode 100644
index 33c6388..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mediaframeworktest.unit;
-
-import android.hardware.camera2.CameraAccessException;
-import android.hardware.camera2.utils.CameraBinderDecorator;
-import android.hardware.camera2.utils.CameraRuntimeException;
-import android.os.DeadObjectException;
-import android.os.RemoteException;
-import android.os.TransactionTooLargeException;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import static org.mockito.Mockito.*;
-import static android.hardware.camera2.utils.CameraBinderDecorator.*;
-import static android.hardware.camera2.CameraAccessException.*;
-import static android.system.OsConstants.*;
-
-import junit.framework.Assert;
-
-public class CameraUtilsBinderDecoratorTest extends junit.framework.TestCase {
-
- private interface ICameraBinderStereotype {
-
- double doNothing();
-
- // int is a 'status_t'
- int doSomethingPositive();
-
- int doSomethingNoError();
-
- int doSomethingPermissionDenied();
-
- int doSomethingAlreadyExists();
-
- int doSomethingBadValue();
-
- int doSomethingDeadObject() throws CameraRuntimeException;
-
- int doSomethingBadPolicy() throws CameraRuntimeException;
-
- int doSomethingDeviceBusy() throws CameraRuntimeException;
-
- int doSomethingNoSuchDevice() throws CameraRuntimeException;
-
- int doSomethingUnknownErrorCode();
-
- int doSomethingThrowDeadObjectException() throws RemoteException;
-
- int doSomethingThrowTransactionTooLargeException() throws RemoteException;
- }
-
- private static final double SOME_ARBITRARY_DOUBLE = 1.0;
- private static final int SOME_ARBITRARY_POSITIVE_INT = 5;
- private static final int SOME_ARBITRARY_NEGATIVE_INT = -0xC0FFEE;
-
- @SmallTest
- public void testStereotypes() {
-
- ICameraBinderStereotype mock = mock(ICameraBinderStereotype.class);
- try {
- when(mock.doNothing()).thenReturn(SOME_ARBITRARY_DOUBLE);
- when(mock.doSomethingPositive()).thenReturn(SOME_ARBITRARY_POSITIVE_INT);
- when(mock.doSomethingNoError()).thenReturn(NO_ERROR);
- when(mock.doSomethingPermissionDenied()).thenReturn(PERMISSION_DENIED);
- when(mock.doSomethingAlreadyExists()).thenReturn(ALREADY_EXISTS);
- when(mock.doSomethingBadValue()).thenReturn(BAD_VALUE);
- when(mock.doSomethingDeadObject()).thenReturn(DEAD_OBJECT);
- when(mock.doSomethingBadPolicy()).thenReturn(-EACCES);
- when(mock.doSomethingDeviceBusy()).thenReturn(-EBUSY);
- when(mock.doSomethingNoSuchDevice()).thenReturn(-ENODEV);
- when(mock.doSomethingUnknownErrorCode()).thenReturn(SOME_ARBITRARY_NEGATIVE_INT);
- when(mock.doSomethingThrowDeadObjectException()).thenThrow(new DeadObjectException());
- when(mock.doSomethingThrowTransactionTooLargeException()).thenThrow(
- new TransactionTooLargeException());
- } catch (RemoteException e) {
- Assert.fail("Unreachable");
- }
-
- ICameraBinderStereotype decoratedMock = CameraBinderDecorator.newInstance(mock);
-
- // ignored by decorator because return type is double, not int
- assertEquals(SOME_ARBITRARY_DOUBLE, decoratedMock.doNothing());
-
- // pass through for positive values
- assertEquals(SOME_ARBITRARY_POSITIVE_INT, decoratedMock.doSomethingPositive());
-
- // pass through NO_ERROR
- assertEquals(NO_ERROR, decoratedMock.doSomethingNoError());
-
- try {
- decoratedMock.doSomethingPermissionDenied();
- Assert.fail("Should've thrown SecurityException");
- } catch (SecurityException e) {
- }
-
- assertEquals(ALREADY_EXISTS, decoratedMock.doSomethingAlreadyExists());
-
- try {
- decoratedMock.doSomethingBadValue();
- Assert.fail("Should've thrown IllegalArgumentException");
- } catch (IllegalArgumentException e) {
- }
-
- try {
- decoratedMock.doSomethingDeadObject();
- Assert.fail("Should've thrown CameraRuntimeException");
- } catch (CameraRuntimeException e) {
- assertEquals(CAMERA_DISCONNECTED, e.getReason());
- }
-
- try {
- decoratedMock.doSomethingBadPolicy();
- Assert.fail("Should've thrown CameraRuntimeException");
- } catch (CameraRuntimeException e) {
- assertEquals(CAMERA_DISABLED, e.getReason());
- }
-
- try {
- decoratedMock.doSomethingDeviceBusy();
- Assert.fail("Should've thrown CameraRuntimeException");
- } catch (CameraRuntimeException e) {
- assertEquals(CAMERA_IN_USE, e.getReason());
- }
-
- try {
- decoratedMock.doSomethingNoSuchDevice();
- Assert.fail("Should've thrown CameraRuntimeException");
- } catch (CameraRuntimeException e) {
- assertEquals(CAMERA_DISCONNECTED, e.getReason());
- }
-
- try {
- decoratedMock.doSomethingUnknownErrorCode();
- Assert.fail("Should've thrown UnsupportedOperationException");
- } catch (UnsupportedOperationException e) {
- assertEquals(String.format("Unknown error %d",
- SOME_ARBITRARY_NEGATIVE_INT), e.getMessage());
- }
-
- try {
- decoratedMock.doSomethingThrowDeadObjectException();
- Assert.fail("Should've thrown CameraRuntimeException");
- } catch (CameraRuntimeException e) {
- assertEquals(CAMERA_DISCONNECTED, e.getReason());
- } catch (RemoteException e) {
- Assert.fail("Should not throw a DeadObjectException directly, but rethrow");
- }
-
- try {
- decoratedMock.doSomethingThrowTransactionTooLargeException();
- Assert.fail("Should've thrown UnsupportedOperationException");
- } catch (UnsupportedOperationException e) {
- assertTrue(e.getCause() instanceof TransactionTooLargeException);
- } catch (RemoteException e) {
- Assert.fail("Should not throw a TransactionTooLargeException directly, but rethrow");
- }
- }
-
-}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsDecoratorTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsDecoratorTest.java
deleted file mode 100644
index c3b6006..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsDecoratorTest.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mediaframeworktest.unit;
-
-import android.test.suitebuilder.annotation.SmallTest;
-import android.hardware.camera2.utils.*;
-import android.hardware.camera2.utils.Decorator.DecoratorListener;
-
-import junit.framework.Assert;
-
-import java.lang.reflect.Method;
-
-/**
- * adb shell am instrument -e class 'com.android.mediaframeworktest.unit.CameraUtilsDecoratorTest' \
- * -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner
- */
-public class CameraUtilsDecoratorTest extends junit.framework.TestCase {
- private DummyListener mDummyListener;
- private DummyInterface mIface;
-
- @Override
- public void setUp() {
- mDummyListener = new DummyListener();
- mIface = Decorator.newInstance(new DummyImpl(), mDummyListener);
- }
-
- interface DummyInterface {
- int addValues(int x, int y, int z);
-
- void raiseException() throws Exception;
-
- void raiseUnsupportedOperationException() throws UnsupportedOperationException;
- }
-
- class DummyImpl implements DummyInterface {
- @Override
- public int addValues(int x, int y, int z) {
- return x + y + z;
- }
-
- @Override
- public void raiseException() throws Exception {
- throw new Exception("Test exception");
- }
-
- @Override
- public void raiseUnsupportedOperationException() throws UnsupportedOperationException {
- throw new UnsupportedOperationException("Test exception");
- }
- }
-
- class DummyListener implements DecoratorListener {
-
- public boolean beforeCalled = false;
- public boolean afterCalled = false;
- public boolean catchCalled = false;
- public boolean finallyCalled = false;
- public Object resultValue = null;
-
- public boolean raiseException = false;
-
- @Override
- public void onBeforeInvocation(Method m, Object[] args) {
- beforeCalled = true;
- }
-
- @Override
- public void onAfterInvocation(Method m, Object[] args, Object result) {
- afterCalled = true;
- resultValue = result;
-
- if (raiseException) {
- throw new UnsupportedOperationException("Test exception");
- }
- }
-
- @Override
- public boolean onCatchException(Method m, Object[] args, Throwable t) {
- catchCalled = true;
- return false;
- }
-
- @Override
- public void onFinally(Method m, Object[] args) {
- finallyCalled = true;
- }
-
- };
-
- @SmallTest
- public void testDecorator() {
-
- // TODO rewrite this using mocks
-
- assertTrue(mIface.addValues(1, 2, 3) == 6);
- assertTrue(mDummyListener.beforeCalled);
- assertTrue(mDummyListener.afterCalled);
-
- int resultValue = (Integer)mDummyListener.resultValue;
- assertTrue(resultValue == 6);
- assertTrue(mDummyListener.finallyCalled);
- assertFalse(mDummyListener.catchCalled);
- }
-
- @SmallTest
- public void testDecoratorExceptions() {
-
- boolean gotExceptions = false;
- try {
- mIface.raiseException();
- } catch (Exception e) {
- gotExceptions = true;
- assertTrue(e.getMessage() == "Test exception");
- }
- assertTrue(gotExceptions);
- assertTrue(mDummyListener.beforeCalled);
- assertFalse(mDummyListener.afterCalled);
- assertTrue(mDummyListener.catchCalled);
- assertTrue(mDummyListener.finallyCalled);
- }
-
- @SmallTest
- public void testDecoratorUnsupportedOperationException() {
-
- boolean gotExceptions = false;
- try {
- mIface.raiseUnsupportedOperationException();
- } catch (UnsupportedOperationException e) {
- gotExceptions = true;
- assertTrue(e.getMessage() == "Test exception");
- }
- assertTrue(gotExceptions);
- assertTrue(mDummyListener.beforeCalled);
- assertFalse(mDummyListener.afterCalled);
- assertTrue(mDummyListener.catchCalled);
- assertTrue(mDummyListener.finallyCalled);
- }
-
- @SmallTest
- public void testDecoratorRaisesException() {
-
- boolean gotExceptions = false;
- try {
- mDummyListener.raiseException = true;
- mIface.addValues(1, 2, 3);
- Assert.fail("unreachable");
- } catch (UnsupportedOperationException e) {
- gotExceptions = true;
- assertTrue(e.getMessage() == "Test exception");
- }
- assertTrue(gotExceptions);
- assertTrue(mDummyListener.beforeCalled);
- assertTrue(mDummyListener.afterCalled);
- assertFalse(mDummyListener.catchCalled);
- assertTrue(mDummyListener.finallyCalled);
- }
-}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsRuntimeExceptionTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsRuntimeExceptionTest.java
deleted file mode 100644
index 02c9f2a..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsRuntimeExceptionTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mediaframeworktest.unit;
-
-import android.hardware.camera2.CameraAccessException;
-import android.hardware.camera2.utils.CameraRuntimeException;
-import android.hardware.camera2.utils.UncheckedThrow;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.Assert;
-
-public class CameraUtilsRuntimeExceptionTest extends junit.framework.TestCase {
-
- @SmallTest
- public void testCameraRuntimeException1() {
- try {
- CameraRuntimeException runtimeExc = new CameraRuntimeException(12345);
- throw runtimeExc.asChecked();
- } catch (CameraAccessException e) {
- assertEquals(12345, e.getReason());
- assertNull(e.getMessage());
- assertNull(e.getCause());
- }
- }
-
- @SmallTest
- public void testCameraRuntimeException2() {
- try {
- CameraRuntimeException runtimeExc = new CameraRuntimeException(12345, "Hello");
- throw runtimeExc.asChecked();
- } catch (CameraAccessException e) {
- assertEquals(12345, e.getReason());
- assertEquals("Hello", e.getMessage());
- assertNull(e.getCause());
- }
- }
-
- @SmallTest
- public void testCameraRuntimeException3() {
- Throwable cause = new IllegalStateException("For great justice");
- try {
- CameraRuntimeException runtimeExc = new CameraRuntimeException(12345, cause);
- throw runtimeExc.asChecked();
- } catch (CameraAccessException e) {
- assertEquals(12345, e.getReason());
- assertNull(e.getMessage());
- assertEquals(cause, e.getCause());
- }
- }
-
- @SmallTest
- public void testCameraRuntimeException4() {
- Throwable cause = new IllegalStateException("For great justice");
- try {
- CameraRuntimeException runtimeExc = new CameraRuntimeException(12345, "Hello", cause);
- throw runtimeExc.asChecked();
- } catch (CameraAccessException e) {
- assertEquals(12345, e.getReason());
- assertEquals("Hello", e.getMessage());
- assertEquals(cause, e.getCause());
- }
- }
-}
diff --git a/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java
index 05fd2f7..bf056f1 100644
--- a/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java
+++ b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java
@@ -121,7 +121,7 @@
activity.removeEventListener(listener);
}
- assertEquals(i, measurements.size());
+ assertEquals(i + 1, measurements.size());
// Go back to the empty root.
bots.roots.openRoot(STRESS_ROOT_0_ID);
diff --git a/packages/DocumentsUI/res/drawable/ic_sd_storage.xml b/packages/DocumentsUI/res/drawable/ic_sd_storage.xml
index b0f3cc3..5aeebbb 100644
--- a/packages/DocumentsUI/res/drawable/ic_sd_storage.xml
+++ b/packages/DocumentsUI/res/drawable/ic_sd_storage.xml
@@ -14,8 +14,8 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
+ android:width="24dp"
+ android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
diff --git a/packages/DocumentsUI/res/drawable/ic_usb_storage.xml b/packages/DocumentsUI/res/drawable/ic_usb_storage.xml
new file mode 100644
index 0000000..2a8d024
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_usb_storage.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M15 7v4h1v2h-3V5h2l-3,-4,-3 4h2v8H8v-2.07c.7,-.37 1.2,-1.08 1.2,-1.93 0,-1.21,-.99,-2.2,-2.2,-2.2,-1.21 0,-2.2.99,-2.2 2.2 0 .85.5 1.56 1.2 1.93V13c0 1.11.89 2 2 2h3v3.05c-.71.37,-1.2 1.1,-1.2 1.95 0 1.22.99 2.2 2.2 2.2 1.21 0 2.2,-.98 2.2,-2.2 0,-.85,-.49,-1.58,-1.2,-1.95V15h3c1.11 0 2,-.89 2,-2v-2h1V7h-4z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/layout/dialog_delete_confirmation.xml b/packages/DocumentsUI/res/layout/dialog_delete_confirmation.xml
new file mode 100644
index 0000000..990ce0b
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/dialog_delete_confirmation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingTop="30dp"
+ android:gravity="center"
+ android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+ android:textColor="@*android:color/primary_text_default_material_light">
+</TextView>
diff --git a/packages/DocumentsUI/res/layout/drawer_layout.xml b/packages/DocumentsUI/res/layout/drawer_layout.xml
index 065102b..09f4401 100644
--- a/packages/DocumentsUI/res/layout/drawer_layout.xml
+++ b/packages/DocumentsUI/res/layout/drawer_layout.xml
@@ -46,6 +46,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
+ android:popupTheme="?actionBarPopupTheme"
android:overlapAnchor="true" />
</com.android.documentsui.DocumentsToolbar>
diff --git a/packages/DocumentsUI/res/layout/fixed_layout.xml b/packages/DocumentsUI/res/layout/fixed_layout.xml
index 84a928d..9f7296b 100644
--- a/packages/DocumentsUI/res/layout/fixed_layout.xml
+++ b/packages/DocumentsUI/res/layout/fixed_layout.xml
@@ -44,6 +44,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
+ android:popupTheme="?actionBarPopupTheme"
android:overlapAnchor="true" />
</com.android.documentsui.DocumentsToolbar>
diff --git a/packages/DocumentsUI/res/layout/item_subdir.xml b/packages/DocumentsUI/res/layout/item_subdir.xml
index b8251d1..ffe4afe 100644
--- a/packages/DocumentsUI/res/layout/item_subdir.xml
+++ b/packages/DocumentsUI/res/layout/item_subdir.xml
@@ -24,16 +24,6 @@
android:orientation="horizontal"
android:baselineAligned="false">
- <ImageView
- android:id="@+id/subdir"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:paddingEnd="8dp"
- android:scaleType="centerInside"
- android:visibility="gone"
- android:src="@drawable/ic_subdirectory_arrow"
- android:contentDescription="@null" />
-
<TextView
android:id="@android:id/title"
android:layout_width="0dp"
diff --git a/packages/DocumentsUI/res/layout/single_pane_layout.xml b/packages/DocumentsUI/res/layout/single_pane_layout.xml
index 235d22d..8bf023f 100644
--- a/packages/DocumentsUI/res/layout/single_pane_layout.xml
+++ b/packages/DocumentsUI/res/layout/single_pane_layout.xml
@@ -43,6 +43,7 @@
android:id="@+id/stack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:popupTheme="?actionBarPopupTheme"
android:layout_marginStart="4dp"
android:overlapAnchor="true" />
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 3dc111a..6e1b30e 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -208,11 +208,9 @@
<string name="allow">Allow</string>
<!-- Text in the button asking user to deny access to a given directory. -->
<string name="deny">Deny</string>
- <!-- Dialog title shown to users when asking if they want to delete files (a confirmation). -->
- <string name="delete_confirmation_title">Delete files?</string>
<!-- Dialog text shown to users when asking if they want to delete files (a confirmation). -->
<plurals name="delete_confirmation_message">
- <item quantity="one">Are you sure you want to delete <xliff:g id="count" example="1">%1$d</xliff:g> file?</item>
- <item quantity="other">Are you sure you want to delete <xliff:g id="count" example="3">%1$d</xliff:g> files?</item>
+ <item quantity="one">Delete <xliff:g id="count" example="1">%1$d</xliff:g> file?</item>
+ <item quantity="other">Delete <xliff:g id="count" example="3">%1$d</xliff:g> files?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index 40bd754..ebc9082 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -82,6 +82,9 @@
builder.setNegativeButton(android.R.string.cancel, null);
final AlertDialog dialog = builder.create();
+ // Workaround for the problem - virtual keyboard doesn't show on the phone.
+ Shared.ensureKeyboardPresent(context, dialog);
+
editText.setOnEditorActionListener(
new OnEditorActionListener() {
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
index 4cba135..c520204 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
@@ -220,17 +220,14 @@
.inflate(R.layout.item_subdir, parent, false);
}
- final ImageView subdir = (ImageView) convertView.findViewById(R.id.subdir);
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
final DocumentInfo doc = getItem(position);
if (position == 0) {
final RootInfo root = mEnv.getCurrentRoot();
title.setText(root.title);
- subdir.setVisibility(View.GONE);
} else {
title.setText(doc.displayName);
- subdir.setVisibility(View.VISIBLE);
}
return convertView;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index 99c2d80..26900a7 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -17,9 +17,12 @@
package com.android.documentsui;
import android.content.Context;
+import android.content.res.Configuration;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Time;
+import android.view.WindowManager;
+import android.app.AlertDialog;
import java.text.Collator;
import java.util.ArrayList;
@@ -155,4 +158,15 @@
return sCollator.compare(lhs, rhs);
}
+
+ public static boolean isHardwareKeyboardAvailable(Context context) {
+ return context.getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS;
+ }
+
+ public static void ensureKeyboardPresent(Context context, AlertDialog dialog) {
+ if (!isHardwareKeyboardAvailable(context)) {
+ dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+ }
+ }
+
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 1348a58..83838d3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -168,6 +168,7 @@
private GridLayoutManager mLayout;
private int mColumnCount = 1; // This will get updated when layout changes.
+ private LayoutInflater mInflater;
private MessageBar mMessageBar;
private View mProgressBar;
@@ -182,13 +183,12 @@
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ mInflater = inflater;
final View view = inflater.inflate(R.layout.fragment_directory, container, false);
mMessageBar = MessageBar.create(getChildFragmentManager());
mProgressBar = view.findViewById(R.id.progressbar);
-
mEmptyView = view.findViewById(android.R.id.empty);
-
mRecView = (RecyclerView) view.findViewById(R.id.dir_list);
mRecView.setRecyclerListener(
new RecyclerListener() {
@@ -708,13 +708,27 @@
new GetDocumentsTask() {
@Override
void onDocumentsReady(final List<DocumentInfo> docs) {
+
+ TextView message =
+ (TextView) mInflater.inflate(R.layout.dialog_delete_confirmation, null);
+ message.setText(
+ Shared.getQuantityString(
+ getActivity(),
+ R.plurals.delete_confirmation_message,
+ docs.size()));
+
+ // This "insta-hides" files that are being deleted, because
+ // the delete operation may be not execute immediately (it
+ // may be queued up on the FileOperationService.)
+ // To hide the files locally, we call the hide method on the adapter
+ // ...which a live object...cannot be parceled.
+ // For that reason, for now, we implement this dialog NOT
+ // as a fragment (which can survive rotation and have its own state),
+ // but as a simple runtime dialog. So rotating a device with an
+ // active delete dialog...results in that dialog disappearing.
+ // We can do better, but don't have cycles for it now.
new AlertDialog.Builder(getActivity())
- .setTitle(R.string.delete_confirmation_title)
- .setMessage(
- Shared.getQuantityString(
- getActivity(),
- R.plurals.delete_confirmation_message,
- docs.size()))
+ .setView(message)
.setPositiveButton(
android.R.string.yes,
new DialogInterface.OnClickListener() {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
index 0930c22..0bbecf9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
@@ -74,13 +74,6 @@
abstract public SparseArray<String> hide(String... ids);
/**
- * Unhides a set of previously hidden items.
- *
- * @param ids A sparse array of IDs from a previous call to {@link #hide}.
- */
- abstract void unhide(SparseArray<String> ids);
-
- /**
* Returns a class that yields the span size for a particular element. This is
* primarily useful in {@link SectionBreakDocumentsAdapterWrapper} where
* we adjust sizes.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
index 11f9aa7..0831dbf 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
@@ -52,13 +52,14 @@
super(context, parent, R.layout.item_doc_list);
mTitle = (TextView) itemView.findViewById(android.R.id.title);
- mDetails = (LinearLayout) itemView.findViewById(R.id.line2);
mDate = (TextView) itemView.findViewById(R.id.date);
mSize = (TextView) itemView.findViewById(R.id.size);
mSummary = (TextView) itemView.findViewById(android.R.id.summary);
mIconMime = (ImageView) itemView.findViewById(R.id.icon_mime);
mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
mIconCheck = (ImageView) itemView.findViewById(R.id.icon_check);
+ // Warning: mDetails view doesn't exists in layout-sw720dp-land layout
+ mDetails = (LinearLayout) itemView.findViewById(R.id.line2);
mIconHelper = iconHelper;
}
@@ -110,11 +111,11 @@
mTitle.setVisibility(View.VISIBLE);
- // Note, we don't show any details for any directory...ever.
+ boolean hasDetails = false;
if (isDirectory) {
- mDetails.setVisibility(View.GONE);
+ // Note, we don't show any details for any directory...ever.
+ hasDetails = false;
} else {
- boolean hasDetails = false;
if (docSummary != null) {
hasDetails = true;
mSummary.setText(docSummary);
@@ -123,21 +124,24 @@
mSummary.setVisibility(View.INVISIBLE);
}
- if (docLastModified == -1) {
+ if (docLastModified > 0) {
hasDetails = true;
- mDate.setText(null);
- } else {
mDate.setText(Shared.formatTime(mContext, docLastModified));
+ } else {
+ mDate.setText(null);
}
- if (!state.showSize || docSize == -1) {
+ if (state.showSize && docSize > -1) {
hasDetails = true;
- mSize.setVisibility(View.GONE);
- mDetails.setVisibility(View.GONE);
- } else {
mSize.setVisibility(View.VISIBLE);
mSize.setText(Formatter.formatFileSize(mContext, docSize));
+ } else {
+ mSize.setVisibility(View.GONE);
}
+ }
+
+ // mDetails view doesn't exists in layout-sw720dp-land layout
+ if (mDetails != null) {
mDetails.setVisibility(hasDetails ? View.VISIBLE : View.GONE);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
index 42dba45..2b07339 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
@@ -24,12 +24,12 @@
import android.database.Cursor;
import android.provider.DocumentsContract.Document;
-import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.util.SparseArray;
import android.view.ViewGroup;
import com.android.documentsui.State;
+
import com.google.common.collect.Sets;
import java.util.ArrayList;
@@ -181,29 +181,6 @@
return hiddenItems;
}
- @VisibleForTesting
- @Override
- public void unhide(SparseArray<String> ids) {
- if (DEBUG) Log.d(TAG, "Unhiding ids: " + ids);
-
- // An ArrayList can shrink at runtime...and in fact
- // it does when we clear it completely.
- // This means we can't call add(pos, id) without
- // first checking the list size.
- List<String> oldIds = mModelIds;
- mModelIds = new ArrayList<>(oldIds.size() + ids.size());
- mModelIds.addAll(oldIds);
-
- // Finally insert the unhidden items.
- for (int i = 0; i < ids.size(); i++) {
- int pos = ids.keyAt(i);
- String id = ids.get(pos);
- mHiddenIds.remove(id);
- mModelIds.add(pos, id);
- notifyItemInserted(pos);
- }
- }
-
@Override
public List<String> getModelIds() {
return mModelIds;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
index 0018d01..884abbb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
@@ -92,6 +92,9 @@
final AlertDialog dialog = builder.create();
+ // Workaround for the problem - virtual keyboard doesn't show on the phone.
+ Shared.ensureKeyboardPresent(context, dialog);
+
mEditText.setOnEditorActionListener(
new OnEditorActionListener() {
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
index 3ee5cfc..b698059 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
@@ -169,13 +169,6 @@
}
@Override
- void unhide(SparseArray<String> ids) {
- // NOTE: We hear about these changes and adjust break position
- // in our AdapterDataObserver.
- mDelegate.unhide(ids);
- }
-
- @Override
List<String> getModelIds() {
return mDelegate.getModelIds();
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 29273a3..3eaf10a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -16,6 +16,7 @@
package com.android.documentsui.model;
+import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.Shared.compareToIgnoreCaseNullable;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
@@ -31,6 +32,7 @@
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
import android.text.TextUtils;
+import android.util.Log;
import com.android.documentsui.IconUtils;
import com.android.documentsui.R;
@@ -47,6 +49,8 @@
* Representation of a {@link Root}.
*/
public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> {
+
+ private static final String TAG = "RootInfo";
private static final int VERSION_INIT = 1;
private static final int VERSION_DROP_TYPE = 2;
@@ -59,6 +63,8 @@
TYPE_DOWNLOADS,
TYPE_LOCAL,
TYPE_MTP,
+ TYPE_SD,
+ TYPE_USB,
TYPE_OTHER
})
@Retention(RetentionPolicy.SOURCE)
@@ -70,7 +76,9 @@
public static final int TYPE_DOWNLOADS = 5;
public static final int TYPE_LOCAL = 6;
public static final int TYPE_MTP = 7;
- public static final int TYPE_OTHER = 8;
+ public static final int TYPE_SD = 8;
+ public static final int TYPE_USB = 9;
+ public static final int TYPE_OTHER = 10;
public String authority;
public String rootId;
@@ -185,33 +193,40 @@
private void deriveFields() {
derivedMimeTypes = (mimeTypes != null) ? mimeTypes.split("\n") : null;
- // TODO: remove these special case icons
if (isHome()) {
+ derivedType = TYPE_LOCAL;
derivedIcon = R.drawable.ic_root_documents;
- derivedType = TYPE_LOCAL;
- } else if (isExternalStorage()) {
- derivedIcon = R.drawable.ic_root_smartphone;
- derivedType = TYPE_LOCAL;
- // TODO: Apply SD card icon to SD devices.
- } else if (isDownloads()) {
- derivedIcon = R.drawable.ic_root_download;
- derivedType = TYPE_DOWNLOADS;
- } else if (isImages()) {
- derivedIcon = R.drawable.ic_doc_image;
- derivedType = TYPE_IMAGES;
- } else if (isVideos()) {
- derivedIcon = R.drawable.ic_doc_video;
- derivedType = TYPE_VIDEO;
- } else if (isAudio()) {
- derivedIcon = R.drawable.ic_doc_audio;
- derivedType = TYPE_AUDIO;
- } else if (isRecents()) {
- derivedType = TYPE_RECENTS;
} else if (isMtp()) {
derivedType = TYPE_MTP;
+ derivedIcon = R.drawable.ic_usb_storage;
+ } else if (isUsb()) {
+ derivedType = TYPE_USB;
+ derivedIcon = R.drawable.ic_usb_storage;
+ } else if (isSd()) {
+ derivedType = TYPE_SD;
+ derivedIcon = R.drawable.ic_sd_storage;
+ } else if (isExternalStorage()) {
+ derivedType = TYPE_LOCAL;
+ derivedIcon = R.drawable.ic_root_smartphone;
+ } else if (isDownloads()) {
+ derivedType = TYPE_DOWNLOADS;
+ derivedIcon = R.drawable.ic_root_download;
+ } else if (isImages()) {
+ derivedType = TYPE_IMAGES;
+ derivedIcon = R.drawable.ic_doc_image;
+ } else if (isVideos()) {
+ derivedType = TYPE_VIDEO;
+ derivedIcon = R.drawable.ic_doc_video;
+ } else if (isAudio()) {
+ derivedType = TYPE_AUDIO;
+ derivedIcon = R.drawable.ic_doc_audio;
+ } else if (isRecents()) {
+ derivedType = TYPE_RECENTS;
} else {
derivedType = TYPE_OTHER;
}
+
+ if (DEBUG) Log.d(TAG, "Finished deriving fields: " + this);
}
public Uri getUri() {
@@ -291,6 +306,14 @@
return (flags & Root.FLAG_EMPTY) != 0;
}
+ public boolean isSd() {
+ return (flags & Root.FLAG_REMOVABLE_SD) != 0;
+ }
+
+ public boolean isUsb() {
+ return (flags & Root.FLAG_REMOVABLE_USB) != 0;
+ }
+
public Drawable loadIcon(Context context) {
if (derivedIcon != 0) {
return context.getDrawable(derivedIcon);
@@ -358,7 +381,14 @@
@Override
public String toString() {
- return "Root{authority=" + authority + ", rootId=" + rootId + ", title=" + title + "}";
+ return "Root{"
+ + "authority=" + authority
+ + ", rootId=" + rootId
+ + ", title=" + title
+ + ", isUsb=" + isUsb()
+ + ", isSd=" + isSd()
+ + ", isMtp=" + isMtp()
+ + "}";
}
public String getDirectoryString() {
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
index 2244be9..adc8141 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
@@ -73,28 +73,6 @@
assertEquals(mModel.getItemCount() - 2, mAdapter.getItemCount());
}
- // Tests that the items can be hidden and unhidden.
- public void testUnhide_ItemCount() {
- List<String> ids = mModel.getModelIds();
- SparseArray<String> hidden = mAdapter.hide(ids.toArray(new String[ids.size()]));
- mAdapter.unhide(hidden);
- assertEquals(mModel.getItemCount(), mAdapter.getItemCount());
- }
-
- // Tests that the items can be hidden and unhidden.
- public void testUnhide_PreservesOrder() {
- List<String> ids = mModel.getModelIds();
- SparseArray<String> hidden = mAdapter.hide(
- ids.get(0), ids.get(1), ids.get(5), ids.get(9));
- mAdapter.unhide(hidden);
-
- // Finally ensure the restored items are in the original order
- // by checking them against the model.
- for (int i = 0; i < mAdapter.getItemCount(); i++) {
- assertEquals(mModel.idForPosition(i), mAdapter.getModelId(i));
- }
- }
-
private final class TestEnvironment implements DocumentsAdapter.Environment {
private final Context testContext;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java
index 267f47d..e170dbb 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java
@@ -61,11 +61,6 @@
}
@Override
- void unhide(SparseArray<String> ids) {
- throw new UnsupportedOperationException();
- }
-
- @Override
public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
throw new UnsupportedOperationException();
}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index d31a121..9a51b05 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -34,6 +34,7 @@
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor.OnCloseListener;
import android.os.UserHandle;
+import android.os.storage.DiskInfo;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.provider.DocumentsContract;
@@ -41,6 +42,7 @@
import android.provider.DocumentsContract.Root;
import android.provider.DocumentsProvider;
import android.provider.MediaStore;
+import android.provider.Settings;
import android.support.provider.DocumentArchiveHelper;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -62,6 +64,7 @@
public class ExternalStorageProvider extends DocumentsProvider {
private static final String TAG = "ExternalStorage";
+ private static final boolean DEBUG = false;
private static final boolean LOG_INOTIFY = false;
public static final String AUTHORITY = "com.android.externalstorage.documents";
@@ -136,10 +139,25 @@
if (volume.getType() == VolumeInfo.TYPE_EMULATED) {
// We currently only support a single emulated volume mounted at
// a time, and it's always considered the primary
+ if (DEBUG) Log.d(TAG, "Found primary volume: " + volume);
rootId = ROOT_ID_PRIMARY_EMULATED;
+
if (VolumeInfo.ID_EMULATED_INTERNAL.equals(volume.getId())) {
- title = getContext().getString(R.string.root_internal_storage);
+ // This is basically the user's primary device storage.
+ // Use device name for the volume since this is likely same thing
+ // the user sees when they mount their phone on another device.
+ String deviceName = Settings.Global.getString(
+ getContext().getContentResolver(), Settings.Global.DEVICE_NAME);
+
+ // Device name should always be set. In case it isn't, though,
+ // fall back to a localized "Internal Storage" string.
+ title = !TextUtils.isEmpty(deviceName)
+ ? deviceName
+ : getContext().getString(R.string.root_internal_storage);
} else {
+ // This should cover all other storage devices, like an SD card
+ // or USB OTG drive plugged in. Using getBestVolumeDescription()
+ // will give us a nice string like "Samsung SD card" or "SanDisk USB drive"
final VolumeInfo privateVol = mStorageManager.findPrivateForEmulated(volume);
title = mStorageManager.getBestVolumeDescription(privateVol);
}
@@ -167,6 +185,14 @@
root.flags = Root.FLAG_LOCAL_ONLY
| Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD;
+ final DiskInfo disk = volume.getDisk();
+ if (DEBUG) Log.d(TAG, "Disk for root " + rootId + " is " + disk);
+ if (disk != null && disk.isSd()) {
+ root.flags |= Root.FLAG_REMOVABLE_SD;
+ } else if (disk != null && disk.isUsb()) {
+ root.flags |= Root.FLAG_REMOVABLE_USB;
+ }
+
if (volume.isPrimary()) {
// save off the primary volume for subsequent "Home" dir initialization.
primaryVolume = volume;
@@ -192,8 +218,9 @@
}
}
- // Finally, if primary storage is available we add the "Home" directory,
- // creating it as needed.
+ // Finally, if primary storage is available we add the "Documents" directory.
+ // If I recall correctly the actual directory is created on demand
+ // by calling either getPathForUser, or getInternalPathForUser.
if (primaryVolume != null && primaryVolume.isVisible()) {
final RootInfo root = new RootInfo();
root.rootId = ROOT_ID_HOME;
@@ -210,8 +237,7 @@
root.flags |= Root.FLAG_SUPPORTS_CREATE;
}
- // Create the "Home" directory on disk, but don't the localized root.title
- // since the directories shouldn't be localized.
+ // Create the "Documents" directory on disk (don't use the localized title).
root.visiblePath = new File(
primaryVolume.getPathForUser(userId), Environment.DIRECTORY_DOCUMENTS);
root.path = new File(
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 409f6a7..b1d42e7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -519,6 +519,9 @@
@Override
public void showPromptReason(int reason) {
if (mCurrentSecuritySelection != SecurityMode.None) {
+ if (reason != PROMPT_REASON_NONE) {
+ Log.i(TAG, "Strong auth required, reason: " + reason);
+ }
getSecurityView(mCurrentSecuritySelection).showPromptReason(reason);
}
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 64f5cc6..4b62f24 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -731,7 +731,10 @@
// The activity is a component name, therefore it is one or none.
if (resolvedActivities.get(0).activityInfo.exported) {
- intent.putExtra(PrintService.EXTRA_PRINT_JOB_INFO, mPrintJob);
+ PrintJobInfo.Builder printJobBuilder = new PrintJobInfo.Builder(mPrintJob);
+ printJobBuilder.setPages(mSelectedPages);
+
+ intent.putExtra(PrintService.EXTRA_PRINT_JOB_INFO, printJobBuilder.build());
intent.putExtra(PrintService.EXTRA_PRINTER_INFO, printer);
intent.putExtra(PrintService.EXTRA_PRINT_DOCUMENT_INFO,
mPrintedDocument.getDocumentInfo().info);
@@ -759,10 +762,14 @@
// Take the advanced options without interpretation.
mPrintJob.setAdvancedOptions(printJobInfo.getAdvancedOptions());
- // Take copies without interpretation as the advanced print dialog
- // cannot create a print job info with invalid copies.
- mCopiesEditText.setText(String.valueOf(printJobInfo.getCopies()));
- mPrintJob.setCopies(printJobInfo.getCopies());
+ if (printJobInfo.getCopies() < 1) {
+ Log.w(LOG_TAG, "Cannot apply return value from advanced options activity. Copies " +
+ "must be 1 or more. Actual value is: " + printJobInfo.getCopies() + ". " +
+ "Ignoring.");
+ } else {
+ mCopiesEditText.setText(String.valueOf(printJobInfo.getCopies()));
+ mPrintJob.setCopies(printJobInfo.getCopies());
+ }
PrintAttributes currAttributes = mPrintJob.getAttributes();
PrintAttributes newAttributes = printJobInfo.getAttributes();
@@ -771,7 +778,7 @@
// Take the media size only if the current printer supports is.
MediaSize oldMediaSize = currAttributes.getMediaSize();
MediaSize newMediaSize = newAttributes.getMediaSize();
- if (!oldMediaSize.equals(newMediaSize)) {
+ if (newMediaSize != null && !oldMediaSize.equals(newMediaSize)) {
final int mediaSizeCount = mMediaSizeSpinnerAdapter.getCount();
MediaSize newMediaSizePortrait = newAttributes.getMediaSize().asPortrait();
for (int i = 0; i < mediaSizeCount; i++) {
diff --git a/packages/SettingsLib/res/drawable/ic_info.xml b/packages/SettingsLib/res/drawable/ic_info.xml
new file mode 100644
index 0000000..afe7e6b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_info.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/colorAccent">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_settings_lock_outline.xml b/packages/SettingsLib/res/drawable/ic_settings_lock_outline.xml
deleted file mode 100644
index b3d7cf9..0000000
--- a/packages/SettingsLib/res/drawable/ic_settings_lock_outline.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="21dp"
- android:height="21dp"
- android:viewportWidth="21.0"
- android:viewportHeight="21.0"
- android:tint="?android:attr/colorAccent">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M8,16c1.1,0,2-0.9,2-2s-0.9-2-2-2s-2,0.9-2,2S6.9,16,8,16zM14,7h-1V5c0-2.8-2.2-5-5-5S3,2.2,3,5v2H2C0.9,7,0,7.9,0,9v10c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V9C16,7.9,15.1,7,14,7z M4.9,5c0-1.7,1.4-3.1,3.1-3.1s3.1,1.4,3.1,3.1v2H4.9V5z M14,19H2V9h12V19z" />
-</vector>
diff --git a/packages/SettingsLib/res/layout/restricted_icon.xml b/packages/SettingsLib/res/layout/restricted_icon.xml
new file mode 100644
index 0000000..d57fb80
--- /dev/null
+++ b/packages/SettingsLib/res/layout/restricted_icon.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/restricted_icon"
+ android:layout_width="@dimen/restricted_icon_size"
+ android:layout_height="@dimen/restricted_icon_size"
+ android:src="@drawable/ic_info"
+ android:gravity="end|center_vertical" />
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/restricted_switch_widget.xml b/packages/SettingsLib/res/layout/restricted_switch_widget.xml
new file mode 100644
index 0000000..6183812
--- /dev/null
+++ b/packages/SettingsLib/res/layout/restricted_switch_widget.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/restricted_icon"
+ android:layout_width="@dimen/restricted_icon_size"
+ android:layout_height="@dimen/restricted_icon_size"
+ android:src="@drawable/ic_info"
+ android:gravity="end|center_vertical" />
+ <!-- Based off frameworks/base/core/res/res/layout/preference_widget_switch.xml -->
+ <Switch xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+android:id/switch_widget"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="false"
+ android:clickable="false"
+ android:background="@null" />
+</merge>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 9f78e87..c3b3cfc 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -33,8 +33,8 @@
<dimen name="user_spinner_item_height">56dp</dimen>
<!-- Lock icon for preferences locked by admin -->
- <dimen name="restricted_lock_icon_size">16dp</dimen>
- <dimen name="restricted_lock_icon_padding">4dp</dimen>
+ <dimen name="restricted_icon_size">16dp</dimen>
+ <dimen name="restricted_icon_padding">4dp</dimen>
<dimen name="wifi_preference_badge_padding">8dip</dimen>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 72fa939..ae2c6e7 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -773,6 +773,11 @@
<!-- Summary for settings preference disabled by administrator [CHAR LIMIT=50] -->
<string name="disabled_by_admin_summary_text">Controlled by admin</string>
+ <!-- Summary for switch preference to denote it is switched on [CHAR LIMIT=50] -->
+ <string name="enabled_by_admin">Enabled by administrator</string>
+ <!-- Summary for switch preference to denote it is switched on [CHAR LIMIT=50] -->
+ <string name="disabled_by_admin">Disabled by administrator</string>
+
<!-- Option in navigation drawer that leads to Settings main screen [CHAR LIMIT=30] -->
<string name="home">Home</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedDropDownPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedDropDownPreference.java
index c2f885d..4c0450e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedDropDownPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedDropDownPreference.java
@@ -49,7 +49,7 @@
mRestrictedPadlock = RestrictedLockUtils.getRestrictedPadlock(context);
mRestrictedPadlockPadding = context.getResources().getDimensionPixelSize(
- R.dimen.restricted_lock_icon_padding);
+ R.dimen.restricted_icon_padding);
}
private final OnItemSelectedListener mItemSelectedListener = new OnItemSelectedListener() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockImageSpan.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockImageSpan.java
index e63130d..360a34c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockImageSpan.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockImageSpan.java
@@ -36,7 +36,7 @@
mContext = context;
mExtraPadding = mContext.getResources().getDimensionPixelSize(
- R.dimen.restricted_lock_icon_padding);
+ R.dimen.restricted_icon_padding);
mRestrictedPadlock = RestrictedLockUtils.getRestrictedPadlock(mContext);
}
@@ -53,7 +53,7 @@
// Add extra padding before the padlock.
float transX = x + mExtraPadding;
- float transY = bottom - drawable.getBounds().bottom - paint.getFontMetricsInt().descent;
+ float transY = (bottom - drawable.getBounds().bottom) / 2.0f;
canvas.translate(transX, transY);
drawable.draw(canvas);
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index 6d29c5f..d0c249f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -49,9 +49,9 @@
* @return drawables for displaying with settings that are locked by a device admin.
*/
public static Drawable getRestrictedPadlock(Context context) {
- Drawable restrictedPadlock = context.getDrawable(R.drawable.ic_settings_lock_outline);
+ Drawable restrictedPadlock = context.getDrawable(R.drawable.ic_info);
final int iconSize = context.getResources().getDimensionPixelSize(
- R.dimen.restricted_lock_icon_size);
+ R.dimen.restricted_icon_size);
restrictedPadlock.setBounds(0, 0, iconSize, iconSize);
return restrictedPadlock;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
index 810f6eb..e69497a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
@@ -23,6 +23,7 @@
import android.support.v7.preference.PreferenceManager;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet;
+import android.view.View;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
@@ -36,6 +37,7 @@
public RestrictedPreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ setWidgetLayoutResource(R.layout.restricted_icon);
mHelper = new RestrictedPreferenceHelper(context, this, attrs);
}
@@ -56,6 +58,10 @@
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mHelper.onBindViewHolder(holder);
+ final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
+ if (restrictedIcon != null) {
+ restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
+ }
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 227b1e8..0c0af24 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -54,7 +54,7 @@
mRestrictedPadlock = RestrictedLockUtils.getRestrictedPadlock(mContext);
mRestrictedPadlockPadding = mContext.getResources().getDimensionPixelSize(
- R.dimen.restricted_lock_icon_padding);
+ R.dimen.restricted_icon_padding);
if (attrs != null) {
final TypedArray attributes = context.obtainStyledAttributes(attrs,
@@ -91,12 +91,8 @@
* Modify PreferenceViewHolder to add padlock if restriction is disabled.
*/
public void onBindViewHolder(PreferenceViewHolder holder) {
- final TextView titleView = (TextView) holder.findViewById(android.R.id.title);
- if (titleView != null) {
- RestrictedLockUtils.setTextViewPadlock(mContext, titleView, mDisabledByAdmin);
- if (mDisabledByAdmin) {
- holder.itemView.setEnabled(true);
- }
+ if (mDisabledByAdmin) {
+ holder.itemView.setEnabled(true);
}
if (mUseAdminDisabledSummary) {
final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index 6cae8aa..f381286 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -23,6 +23,8 @@
import android.support.v7.preference.PreferenceViewHolder;
import android.support.v14.preference.SwitchPreference;
import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
@@ -36,6 +38,7 @@
public RestrictedSwitchPreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ setWidgetLayoutResource(R.layout.restricted_switch_widget);
mHelper = new RestrictedPreferenceHelper(context, this, attrs);
}
@@ -56,6 +59,20 @@
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mHelper.onBindViewHolder(holder);
+ final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
+ final View switchWidget = holder.findViewById(android.R.id.switch_widget);
+ if (restrictedIcon != null) {
+ restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
+ }
+ if (switchWidget != null) {
+ switchWidget.setVisibility(isDisabledByAdmin() ? View.GONE : View.VISIBLE);
+ }
+ final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
+ if (summaryView != null && isDisabledByAdmin()) {
+ summaryView.setText(
+ isChecked() ? R.string.enabled_by_admin : R.string.disabled_by_admin);
+ summaryView.setVisibility(View.VISIBLE);
+ }
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
index 1859207..741b0ea 100644
--- a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
@@ -25,6 +25,12 @@
import android.util.Log;
import android.util.Pair;
import android.util.Xml;
+import android.provider.Settings;
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.content.ContentValues;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.view.InflateException;
import com.android.settingslib.drawer.Tile;
import com.android.settingslib.drawer.TileUtils;
@@ -42,6 +48,12 @@
// If defined, only returns this suggestion if the feature is supported.
public static final String META_DATA_REQUIRE_FEATURE = "com.android.settings.require_feature";
+ // If defined, only display this optional step if an account of that type exists.
+ private static final String META_DATA_REQUIRE_ACCOUNT = "com.android.settings.require_account";
+
+ // If defined and not true, do not should optional step.
+ private static final String META_DATA_IS_SUPPORTED = "com.android.settings.is_supported";
+
/**
* Allows suggestions to appear after a certain number of days, and to re-appear if dismissed.
* For instance:
@@ -110,7 +122,10 @@
TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
addCache, null, suggestions, true, false);
for (int i = countBefore; i < suggestions.size(); i++) {
- if (!isAvailable(suggestions.get(i)) || isDismissed(suggestions.get(i))) {
+ if (!isAvailable(suggestions.get(i)) ||
+ !isSupported(suggestions.get(i)) ||
+ !satisfiesRequiredAccount(suggestions.get(i)) ||
+ isDismissed(suggestions.get(i))) {
suggestions.remove(i--);
}
}
@@ -124,7 +139,10 @@
item = last;
}
}
- suggestions.add(item);
+ // If category is marked as done, do not add any item.
+ if (!isCategoryDone(category.category)) {
+ suggestions.add(item);
+ }
}
}
@@ -136,6 +154,41 @@
return true;
}
+ public boolean satisfiesRequiredAccount(Tile suggestion) {
+ String requiredAccountType = suggestion.metaData.getString(META_DATA_REQUIRE_ACCOUNT);
+ if (requiredAccountType == null) {
+ return true;
+ }
+ AccountManager accountManager = AccountManager.get(mContext);
+ Account[] accounts = accountManager.getAccountsByType(requiredAccountType);
+ return accounts.length > 0;
+ }
+
+ public boolean isSupported(Tile suggestion) {
+ int isSupportedResource = suggestion.metaData.getInt(META_DATA_IS_SUPPORTED);
+ try {
+ if (suggestion.intent == null) {
+ return false;
+ }
+ final Resources res = mContext.getPackageManager().getResourcesForActivity(
+ suggestion.intent.getComponent());
+ return isSupportedResource != 0 ? res.getBoolean(isSupportedResource) : true;
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Cannot find resources for " + suggestion.intent.getComponent());
+ return false;
+ }
+ }
+
+ public boolean isCategoryDone(String category) {
+ String name = Settings.Secure.COMPLETED_CATEGORY_PREFIX + category;
+ return Settings.Secure.getInt(mContext.getContentResolver(), name, 0) != 0;
+ }
+
+ public void markCategoryDone(String category) {
+ String name = Settings.Secure.COMPLETED_CATEGORY_PREFIX + category;
+ Settings.Secure.putInt(mContext.getContentResolver(), name, 1);
+ }
+
private boolean isDismissed(Tile suggestion) {
Object dismissObj = suggestion.metaData.get(META_DATA_DISMISS_CONTROL);
if (dismissObj == null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index a578055..7a1c741 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -69,16 +69,18 @@
long startTime = System.currentTimeMillis();
- getWindow().addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- getWindow().addFlags(LayoutParams.FLAG_TRANSLUCENT_STATUS);
- requestWindowFeature(Window.FEATURE_NO_TITLE);
+ TypedArray theme = getTheme().obtainStyledAttributes(android.R.styleable.Theme);
+ if (!theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
+ getWindow().addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ getWindow().addFlags(LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ }
super.setContentView(R.layout.settings_with_drawer);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
if (mDrawerLayout == null) {
return;
}
Toolbar toolbar = (Toolbar) findViewById(R.id.action_bar);
- TypedArray theme = getTheme().obtainStyledAttributes(android.R.styleable.Theme);
if (theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
toolbar.setVisibility(View.GONE);
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index 2dfdfda..418b138 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -41,7 +41,7 @@
public class TileUtils {
private static final boolean DEBUG = false;
- private static final boolean DEBUG_TIMING = true;
+ private static final boolean DEBUG_TIMING = false;
private static final String LOG_TAG = "TileUtils";
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 9842e28..a424d55 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1128,10 +1128,15 @@
private PackageInfo getCallingPackageInfoOrThrow(int userId) {
try {
- return mPackageManager.getPackageInfo(getCallingPackage(), 0, userId);
+ PackageInfo packageInfo = mPackageManager.getPackageInfo(
+ getCallingPackage(), 0, userId);
+ if (packageInfo != null) {
+ return packageInfo;
+ }
} catch (RemoteException e) {
- throw new IllegalStateException("Calling package doesn't exist");
+ /* ignore */
}
+ throw new IllegalStateException("Calling package doesn't exist");
}
private int getGroupParentLocked(int userId) {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index b5b7bcd..637551c 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -245,7 +245,7 @@
android:stateNotNeeded="true"
android:resumeWhilePausing="true"
android:screenOrientation="behind"
- android:theme="@style/RecentsTheme.Wallpaper">
+ android:theme="@style/RecentsTvTheme.Wallpaper">
<intent-filter>
<action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
</intent-filter>
diff --git a/packages/SystemUI/res/color/notification_guts_buttons.xml b/packages/SystemUI/res/color/notification_guts_buttons.xml
new file mode 100644
index 0000000..f7a4ee9
--- /dev/null
+++ b/packages/SystemUI/res/color/notification_guts_buttons.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_checked="true"
+ android:color="@*android:color/material_deep_teal_500" />
+ <item android:color="@android:color/black"
+ android:alpha=".87" />
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_info.xml b/packages/SystemUI/res/drawable/ic_info.xml
deleted file mode 100644
index 65e7bf5..0000000
--- a/packages/SystemUI/res/drawable/ic_info.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M12.000000,2.000000C6.500000,2.000000 2.000000,6.500000 2.000000,12.000000s4.500000,10.000000 10.000000,10.000000c5.500000,0.000000 10.000000,-4.500000 10.000000,-10.000000S17.500000,2.000000 12.000000,2.000000zM13.000000,17.000000l-2.000000,0.000000l0.000000,-6.000000l2.000000,0.000000L13.000000,17.000000zM13.000000,9.000000l-2.000000,0.000000L11.000000,7.000000l2.000000,0.000000L13.000000,9.000000z"
- android:fillColor="#FFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/qs_btn_borderless_rect.xml b/packages/SystemUI/res/drawable/qs_btn_borderless_rect.xml
new file mode 100644
index 0000000..03bfd1a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_btn_borderless_rect.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright (C) 2016 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.
+-->
+<inset
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetTop="4dp"
+ android:insetBottom="4dp">
+ <ripple
+ android:color="?android:attr/colorControlHighlight" >
+
+ <item android:id="@android:id/mask">
+ <shape>
+ <corners android:radius="@dimen/borderless_button_radius" />
+
+ <solid android:color="@android:color/white" />
+ </shape>
+ </item>
+
+ </ripple>
+</inset>
diff --git a/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml b/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml
new file mode 100644
index 0000000..e98d43f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <gradient
+ android:startColor="#99000000"
+ android:endColor="#E6000000"
+ android:angle="90"/>
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index 4b0c834..1ab6bf9 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -63,29 +63,32 @@
android:id="@+id/importance_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dip"
+ android:paddingTop="4dp"
+ android:paddingBottom="16dip"
android:paddingEnd="8dp" >
<RadioButton
android:id="@+id/silent_importance"
android:layout_width="wrap_content"
android:layout_height="48dp"
+ android:paddingStart="32dp"
android:text="@string/show_silently"
- style="@style/TextAppearance.NotificationGuts.Primary"
- android:buttonTint="#858383" />
+ style="@style/TextAppearance.NotificationGuts.Radio"
+ android:buttonTint="@color/notification_guts_buttons" />
<RadioButton
android:id="@+id/block_importance"
android:layout_width="wrap_content"
android:layout_height="48dp"
+ android:paddingStart="32dp"
android:text="@string/block"
- style="@style/TextAppearance.NotificationGuts.Primary"
- android:buttonTint="#858383" />
+ style="@style/TextAppearance.NotificationGuts.Radio"
+ android:buttonTint="@color/notification_guts_buttons" />
<RadioButton
android:id="@+id/reset_importance"
android:layout_width="wrap_content"
android:layout_height="48dp"
- style="@style/TextAppearance.NotificationGuts.Primary"
- android:buttonTint="#858383" />
+ android:paddingStart="32dp"
+ style="@style/TextAppearance.NotificationGuts.Radio"
+ android:buttonTint="@color/notification_guts_buttons" />
</RadioGroup>
<!-- Importance slider -->
<LinearLayout
diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
index 603ebbf..b0dca9a 100644
--- a/packages/SystemUI/res/layout/qs_tile_label.xml
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -20,22 +20,22 @@
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView android:id="@+id/tile_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@color/qs_tile_text"
- android:gravity="center_horizontal"
- android:minLines="2"
- android:padding="0dp"
- android:fontFamily="sans-serif-condensed"
- android:textStyle="normal"
- android:textSize="@dimen/qs_tile_text_size"
- android:clickable="false" />
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/qs_tile_text"
+ android:gravity="center_horizontal"
+ android:minLines="2"
+ android:padding="0dp"
+ android:fontFamily="sans-serif-condensed"
+ android:textStyle="normal"
+ android:textSize="@dimen/qs_tile_text_size"
+ android:clickable="false" />
<ImageView android:id="@+id/restricted_padlock"
- android:layout_width="@dimen/qs_tile_text_size"
- android:layout_height="@dimen/qs_tile_text_size"
- android:src="@drawable/ic_settings_lock_outline"
- android:layout_marginLeft="@dimen/restricted_padlock_pading"
- android:baselineAlignBottom="true"
- android:scaleType="centerInside"
- android:visibility="gone" />
+ android:layout_width="@dimen/qs_tile_text_size"
+ android:layout_height="match_parent"
+ android:paddingBottom="@dimen/qs_tile_text_size"
+ android:src="@drawable/ic_info"
+ android:layout_marginLeft="@dimen/restricted_padlock_pading"
+ android:scaleType="centerInside"
+ android:visibility="gone" />
</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index a22c360..661d74a 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -53,10 +53,10 @@
<ImageView
android:id="@+id/restricted_padlock"
android:layout_width="@dimen/qs_detail_item_secondary_text_size"
- android:layout_height="@dimen/qs_detail_item_secondary_text_size"
- android:src="@drawable/ic_settings_lock_outline"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:src="@drawable/ic_info"
android:layout_marginLeft="@dimen/restricted_padlock_pading"
- android:baselineAlignBottom="true"
android:scaleType="centerInside"
android:visibility="gone" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/recents_on_tv.xml b/packages/SystemUI/res/layout/recents_on_tv.xml
index 94b099e..3a7c1d1 100644
--- a/packages/SystemUI/res/layout/recents_on_tv.xml
+++ b/packages/SystemUI/res/layout/recents_on_tv.xml
@@ -18,9 +18,10 @@
android:id="@+id/recents_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:background="@drawable/recents_tv_background_gradient"
android:clipChildren="false"
- android:clipToPadding="false" >
-
+ android:clipToPadding="false"
+ android:layoutDirection="rtl">
<com.android.systemui.recents.tv.views.TaskStackHorizontalGridView
android:id="@+id/task_list"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/recents_task_card_view.xml b/packages/SystemUI/res/layout/recents_tv_task_card_view.xml
similarity index 65%
rename from packages/SystemUI/res/layout/recents_task_card_view.xml
rename to packages/SystemUI/res/layout/recents_tv_task_card_view.xml
index fa1daad..c5b1a7a 100644
--- a/packages/SystemUI/res/layout/recents_task_card_view.xml
+++ b/packages/SystemUI/res/layout/recents_tv_task_card_view.xml
@@ -20,28 +20,28 @@
android:focusable="true"
android:focusableInTouchMode="true"
android:layout_gravity="center"
- android:layout_centerInParent="true">
+ android:layout_centerInParent="true"
+ android:layoutDirection="ltr">
- <RelativeLayout
+ <LinearLayout
android:layout_width="@dimen/recents_tv_card_width"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
- android:layout_gravity="center">
- <ImageView
- android:id="@+id/card_view_thumbnail"
- android:layout_width="match_parent"
- android:layout_height="@dimen/recents_tv_card_height"
- android:scaleType="centerCrop"
- android:gravity="center"
- android:layout_alignParentTop="true"
- android:layout_centerHorizontal="true"/>
-
- <RelativeLayout
+ android:layout_gravity="center"
+ android:orientation="vertical" >
+ <LinearLayout
android:id="@+id/card_info_field"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/card_view_thumbnail"
- android:background="@color/recents_tv_card_background_color" >
+ android:layout_height="wrap_content">
+ <ImageView
+ android:id="@+id/card_extra_badge"
+ android:layout_width="@dimen/recents_tv_card_extra_badge_size"
+ android:layout_height="@dimen/recents_tv_card_extra_badge_size"
+ android:layout_marginBottom="@dimen/recents_tv_icon_padding_bottom"
+ android:layout_marginEnd="@dimen/recents_tv_icon_padding_end"
+ android:scaleType="fitCenter"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true" />
<TextView
android:id="@+id/card_title_text"
android:layout_width="match_parent"
@@ -49,29 +49,21 @@
android:layout_alignParentTop="false"
android:includeFontPadding="true"
android:minLines="1"
- android:maxLines="2"
+ android:maxLines="1"
android:textColor="@color/recents_tv_card_title_text_color"
- android:ellipsize="end" />
- <TextView
- android:id="@+id/card_content_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentStart="true"
- android:layout_below="@id/card_title_text"
- android:includeFontPadding="true"
- android:minLines="1"
- android:maxLines="2"
- android:textColor="@color/recents_tv_card_content_text_color"
- android:ellipsize="end" />
- <ImageView
- android:id="@+id/card_extra_badge"
- android:layout_width="@dimen/recents_tv_card_extra_badge_size"
- android:layout_height="@dimen/recents_tv_card_extra_badge_size"
- android:scaleType="fitCenter"
- android:background="@android:color/transparent"
- android:contentDescription="@null"
- android:layout_centerVertical="true"
- android:layout_alignParentRight="true"/>
- </RelativeLayout>
- </RelativeLayout>
+ android:fontFamily="@string/font_roboto_regular"
+ android:textSize="@dimen/recents_tv_title_text_size"
+ android:layout_marginBottom="@dimen/recents_tv_text_padding_bottom"
+ android:ellipsize="end"/>
+ </LinearLayout>
+ <ImageView
+ android:id="@+id/card_view_thumbnail"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/recents_tv_card_height"
+ android:scaleType="centerCrop"
+ android:gravity="center"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:layout_below="@id/card_title_text" />
+ </LinearLayout>
</com.android.systemui.recents.tv.views.TaskCardView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index 818df3b..75195c4 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -43,7 +43,7 @@
android:singleLine="true"
android:ellipsize="start"
android:inputType="textShortMessage|textAutoCorrect|textCapSentences"
- android:imeOptions="actionSend" />
+ android:imeOptions="actionSend|flagNoExtractUi" />
<FrameLayout
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
index 6f4c983..af99aae 100644
--- a/packages/SystemUI/res/values/colors_tv.xml
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -18,7 +18,5 @@
-->
<resources>
<color name="recents_tv_card_background_color">#FF37474F</color>
- <color name="recents_tv_card_title_text_color">#FFEEEEEE</color>
- <color name="recents_tv_card_content_text_color">#99EEEEEE</color>
- <color name="recents_tv_card_source_text_color">#99EEEEEE</color>
+ <color name="recents_tv_card_title_text_color">#CCEEEEEE</color>
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index fbe0207..12c3a5d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -292,6 +292,9 @@
<!-- The amount to allow the stack to overscroll. -->
<dimen name="recents_stack_overscroll">24dp</dimen>
+ <!-- The size of the initial peek area at the top of the stack (below the status bar). -->
+ <dimen name="recents_initial_top_peek_size">8dp</dimen>
+
<!-- The size of the peek area at the top of the stack (below the status bar). -->
<dimen name="recents_layout_focused_top_peek_size">@dimen/recents_history_button_height</dimen>
@@ -326,9 +329,6 @@
<!-- The minimum amount of top overscroll to go to the quick settings. -->
<dimen name="min_top_overscroll_to_qs">36dp</dimen>
- <!-- The padding to the second card when the notifications collapse. -->
- <dimen name="notification_collapse_second_card_padding">8dp</dimen>
-
<!-- The height of the speed bump view. -->
<dimen name="speed_bump_height">16dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
index bf32cc7..b589110 100644
--- a/packages/SystemUI/res/values/dimens_tv.xml
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -18,15 +18,21 @@
-->
<resources>
<!-- Dimens for recents card in the recents view on tv -->
- <dimen name="recents_tv_card_width">150dip</dimen>
- <dimen name="recents_tv_card_height">85dip</dimen>
- <dimen name="recents_tv_card_extra_badge_size">16dip</dimen>
+ <dimen name="recents_tv_card_width">268dip</dimen>
+ <dimen name="recents_tv_card_height">151dip</dimen>
+ <dimen name="recents_tv_card_extra_badge_size">20dip</dimen>
+ <dimen name="recents_tv_banner_width">114dip</dimen>
+ <dimen name="recents_tv_banner_height">64dip</dimen>
+ <dimen name="recents_tv_banner_margin_top">16dip</dimen>
+ <dimen name="recents_tv_icon_padding_bottom">8dip</dimen>
+ <dimen name="recents_tv_icon_padding_end">12dip</dimen>
+ <dimen name="recents_tv_text_padding_bottom">12dip</dimen>
<!-- Padding for grid view in recents view on tv -->
<dimen name="recents_tv_grid_row_padding">56dip</dimen>
<dimen name="recents_tv_gird_row_top_padding">57dip</dimen>
- <dimen name="recents_tv_grid_max_row_height">200dip</dimen>
- <dimen name="recents_tv_gird_card_spacing">8dip</dimen>
+ <dimen name="recents_tv_grid_max_row_height">268dip</dimen>
+ <dimen name="recents_tv_gird_card_spacing">20dip</dimen>
<!-- Values for focus animation -->
<dimen name="recents_tv_unselected_item_z">6dp</dimen>
@@ -34,4 +40,7 @@
<!-- Extra space around the PIP and its outline in PIP onboarding activity -->
<dimen name="tv_pip_bounds_space">3dp</dimen>
+
+ <!-- Values for text on recents cards on tv -->
+ <dimen name="recents_tv_title_text_size">12sp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index 4f382ea..59cfb1e 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -31,11 +31,13 @@
<string name="pip_cancel" translatable="false">Cancel</string>
<!-- Overlay text on PIP -->
<string name="pip_hold_home" translatable="false">Hold HOME to control PIP</string>
-
<!-- Picture-in-Picture onboarding screen -->
<eat-comment />
<!-- Description for onboarding screen. -->
<string name="pip_onboarding_description" translatable="false">Press and hold the HOME\nbutton to close or control it</string>
<!-- Button to close onboarding screen. -->
<string name="pip_onboarding_button" translatable="false">Got it</string>
+ <!-- Font for Recents -->
+ <!-- DO NOT TRANSLATE -->
+ <string name="font_roboto_regular" translatable="false">sans-serif</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index a51b931..89890d6 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -214,7 +214,7 @@
<style name="QSBorderlessButton">
<item name="android:padding">12dp</item>
- <item name="android:background">@drawable/btn_borderless_rect</item>
+ <item name="android:background">@drawable/qs_btn_borderless_rect</item>
<item name="android:gravity">center</item>
</style>
@@ -323,6 +323,10 @@
<item name="android:textSize">16sp</item>
</style>
+ <style name="TextAppearance.NotificationGuts.Radio">
+ <item name="android:alpha">.87</item>
+ </style>
+
<style name="TextAppearance.NotificationGuts.Button">
<item name="android:textSize">14sp</item>
<item name="android:textAllCaps">true</item>
diff --git a/packages/SystemUI/res/values/styles_tv.xml b/packages/SystemUI/res/values/styles_tv.xml
index 3f0caab..263e1a4 100644
--- a/packages/SystemUI/res/values/styles_tv.xml
+++ b/packages/SystemUI/res/values/styles_tv.xml
@@ -22,4 +22,11 @@
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:backgroundDimEnabled">false</item>
</style>
+
+ <style name="RecentsTvTheme.Wallpaper" parent="@android:style/Theme.Material.NoActionBar.Overscan">
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:backgroundDimEnabled">false</item>
+ <item name="android:colorBackgroundCacheHint">@null</item>
+ <item name="android:windowIsTranslucent">true</item>
+ </style>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 33f3c30..f6dcc11 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -144,7 +144,9 @@
protected Animator getViewTranslationAnimator(View v, float target,
AnimatorUpdateListener listener) {
ObjectAnimator anim = createTranslationAnimation(v, target);
- anim.addUpdateListener(listener);
+ if (listener != null) {
+ anim.addUpdateListener(listener);
+ }
return anim;
}
@@ -370,6 +372,9 @@
};
Animator anim = getViewTranslationAnimator(animView, newPos, updateListener);
+ if (anim == null) {
+ return;
+ }
if (useAccelerateInterpolator) {
anim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
} else {
@@ -411,6 +416,9 @@
};
Animator anim = getViewTranslationAnimator(animView, targetLeft, updateListener);
+ if (anim == null) {
+ return;
+ }
int duration = SNAP_ANIM_LEN;
anim.setDuration(duration);
anim.addListener(new AnimatorListenerAdapter() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 8ccf60d..24b45cc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -167,6 +167,11 @@
}
};
+ public int getColumnCount() {
+ if (mPages.size() == 0) return 0;
+ return mPages.get(0).mColumns;
+ }
+
public static class TilePage extends TileLayout {
private int mMaxRows = 3;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index c643d67..6137349 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -16,6 +16,7 @@
import android.util.Log;
import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
import android.view.View.OnLayoutChangeListener;
import android.view.animation.PathInterpolator;
import android.widget.TextView;
@@ -25,14 +26,20 @@
import com.android.systemui.qs.TouchAnimator.Builder;
import com.android.systemui.qs.TouchAnimator.Listener;
import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
import java.util.ArrayList;
import java.util.Collection;
-public class QSAnimator implements Callback, PageListener, Listener, OnLayoutChangeListener {
+public class QSAnimator implements Callback, PageListener, Listener, OnLayoutChangeListener,
+ OnAttachStateChangeListener, Tunable {
private static final String TAG = "QSAnimator";
+ private static final String ALLOW_FANCY_ANIMATION = "sysui_qs_fancy_anim";
+ private static final String MOVE_FULL_ROWS = "sysui_qs_move_whole_rows";
+
public static final PathInterpolator TRANSLATION_Y_INTERPOLATOR =
new PathInterpolator(.1f, .3f, 1, 1);
@@ -44,34 +51,77 @@
private final QSPanel mQsPanel;
private final QSContainer mQsContainer;
+ private PagedTileLayout mPagedLayout;
+
private boolean mOnFirstPage = true;
private TouchAnimator mFirstPageAnimator;
private TouchAnimator mFirstPageDelayedAnimator;
private TouchAnimator mTranslationYAnimator;
private TouchAnimator mNonfirstPageAnimator;
+ private boolean mOnKeyguard;
+
+ private boolean mAllowFancy;
+ private boolean mFullRows;
+ private int mNumQuickTiles;
+
public QSAnimator(QSContainer container, QuickQSPanel quickPanel, QSPanel panel) {
mQsContainer = container;
mQuickQsPanel = quickPanel;
mQsPanel = panel;
+ mQsPanel.addOnAttachStateChangeListener(this);
container.addOnLayoutChangeListener(this);
QSTileLayout tileLayout = mQsPanel.getTileLayout();
if (tileLayout instanceof PagedTileLayout) {
- ((PagedTileLayout) tileLayout).setPageListener(this);
+ mPagedLayout = ((PagedTileLayout) tileLayout);
+ mPagedLayout.setPageListener(this);
} else {
Log.w(TAG, "QS Not using page layout");
}
}
+ public void setOnKeyguard(boolean onKeyguard) {
+ mOnKeyguard = onKeyguard;
+ if (mOnKeyguard) {
+ clearAnimationState();
+ }
+ }
+
public void setHost(QSTileHost qsh) {
qsh.addCallback(this);
}
@Override
+ public void onViewAttachedToWindow(View v) {
+ TunerService.get(mQsContainer.getContext()).addTunable(this, ALLOW_FANCY_ANIMATION,
+ MOVE_FULL_ROWS, QuickQSPanel.NUM_QUICK_TILES);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ TunerService.get(mQsContainer.getContext()).removeTunable(this);
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (ALLOW_FANCY_ANIMATION.equals(key)) {
+ mAllowFancy = newValue == null || Integer.parseInt(newValue) != 0;
+ if (!mAllowFancy) {
+ clearAnimationState();
+ }
+ } else if (MOVE_FULL_ROWS.equals(key)) {
+ mFullRows = newValue != null && Integer.parseInt(newValue) != 0;
+ } else if (QuickQSPanel.NUM_QUICK_TILES.equals(key)) {
+ mNumQuickTiles = QuickQSPanel.getNumQuickTiles(mQsContainer.getContext());
+ clearAnimationState();
+ }
+ updateAnimators();
+ }
+
+ @Override
public void onPageChanged(boolean isFirst) {
if (mOnFirstPage == isFirst) return;
if (!isFirst) {
- setPosition(1);
clearAnimationState();
}
mOnFirstPage = isFirst;
@@ -85,6 +135,7 @@
int count = 0;
int[] loc1 = new int[2];
int[] loc2 = new int[2];
+ int lastYDiff = 0;
firstPageDelayedBuilder.setStartDelay(EXPANDED_TILE_DELAY);
firstPageBuilder.setListener(this);
translationYBuilder.setInterpolator(TRANSLATION_Y_INTERPOLATOR);
@@ -92,18 +143,20 @@
firstPageDelayedBuilder.addFloat(mQsPanel.getTileLayout(), "alpha", 0, 1);
mAllViews.clear();
mTopFiveQs.clear();
+ mAllViews.add((View) mQsPanel.getTileLayout());
for (QSTile<?> tile : tiles) {
QSTileBaseView tileView = mQsPanel.getTileView(tile);
final TextView label = ((QSTileView) tileView).getLabel();
- if (count++ < 5) {
+ final View tileIcon = tileView.getIcon();
+ if (count < mNumQuickTiles && mAllowFancy) {
// Quick tiles.
QSTileBaseView quickTileView = mQuickQsPanel.getTileView(tile);
- final View tileIcon = tileView.getIcon();
getRelativePosition(loc1, quickTileView.getIcon(), mQsContainer);
getRelativePosition(loc2, tileIcon, mQsContainer);
final int xDiff = loc2[0] - loc1[0];
final int yDiff = loc2[1] - loc1[1];
+ lastYDiff = yDiff;
// Move the quick tile right from its location to the new one.
firstPageBuilder.addFloat(quickTileView, "translationX", 0, xDiff);
translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
@@ -119,20 +172,38 @@
mTopFiveQs.add(tileIcon);
mAllViews.add(tileIcon);
+ mAllViews.add(label);
mAllViews.add(quickTileView);
+ } else if (mFullRows && isIconInAnimatedRow(count)) {
+ firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
+ translationYBuilder.addFloat(label, "translationY", -lastYDiff, 0);
+ translationYBuilder.addFloat(tileIcon, "translationY", -lastYDiff, 0);
+ mAllViews.add(tileIcon);
+ mAllViews.add(label);
}
mAllViews.add(tileView);
mAllViews.add(label);
+ count++;
}
- mFirstPageAnimator = firstPageBuilder.build();
- mFirstPageDelayedAnimator = firstPageDelayedBuilder.build();
- mTranslationYAnimator = translationYBuilder.build();
+ if (mAllowFancy) {
+ mFirstPageAnimator = firstPageBuilder.build();
+ mFirstPageDelayedAnimator = firstPageDelayedBuilder.build();
+ mTranslationYAnimator = translationYBuilder.build();
+ }
mNonfirstPageAnimator = new TouchAnimator.Builder()
.addFloat(mQuickQsPanel, "alpha", 1, 0)
.setEndDelay(.5f)
.build();
}
+ private boolean isIconInAnimatedRow(int count) {
+ if (mPagedLayout == null) {
+ return false;
+ }
+ final int columnCount = mPagedLayout.getColumnCount();
+ return count < ((mNumQuickTiles + columnCount - 1) / columnCount) * columnCount;
+ }
+
private void getRelativePosition(int[] loc1, View view, View parent) {
loc1[0] = 0 + view.getWidth() / 2;
loc1[1] = 0;
@@ -148,7 +219,10 @@
public void setPosition(float position) {
if (mFirstPageAnimator == null) return;
- if (mOnFirstPage) {
+ if (mOnKeyguard) {
+ return;
+ }
+ if (mOnFirstPage && mAllowFancy) {
mQuickQsPanel.setAlpha(1);
mFirstPageAnimator.setPosition(position);
mFirstPageDelayedAnimator.setPosition(position);
@@ -186,12 +260,17 @@
private void clearAnimationState() {
final int N = mAllViews.size();
mQuickQsPanel.setAlpha(0);
+ mQuickQsPanel.setVisibility(View.VISIBLE);
for (int i = 0; i < N; i++) {
View v = mAllViews.get(i);
v.setAlpha(1);
v.setTranslationX(1);
v.setTranslationY(1);
}
+ final int N2 = mTopFiveQs.size();
+ for (int i = 0; i < N2; i++) {
+ mTopFiveQs.get(i).setVisibility(View.VISIBLE);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
index c59da8d..c0c1e4d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
@@ -156,6 +156,7 @@
public void setKeyguardShowing(boolean keyguardShowing) {
if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
mKeyguardShowing = keyguardShowing;
+ mQSAnimator.setOnKeyguard(keyguardShowing);
updateQsState();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 8b826ee..f8a57d0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -26,6 +26,8 @@
import com.android.systemui.R;
import com.android.systemui.qs.QSTile.SignalState;
import com.android.systemui.qs.QSTile.State;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
import java.util.ArrayList;
import java.util.Collection;
@@ -35,6 +37,8 @@
*/
public class QuickQSPanel extends QSPanel {
+ public static final String NUM_QUICK_TILES = "sysui_qqs_count";
+
private int mMaxTiles;
private QSPanel mFullPanel;
private View mHeader;
@@ -52,6 +56,18 @@
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ TunerService.get(mContext).addTunable(mNumTiles, NUM_QUICK_TILES);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ TunerService.get(mContext).removeTunable(mNumTiles);
+ }
+
+ @Override
protected void createCustomizePanel() {
// No customizing from the header.
}
@@ -86,6 +102,7 @@
public void setMaxTiles(int maxTiles) {
mMaxTiles = maxTiles;
+ setTiles(mHost.getTiles());
}
@Override
@@ -114,6 +131,17 @@
super.setTiles(quickTiles);
}
+ private final Tunable mNumTiles = new Tunable() {
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ setMaxTiles(getNumQuickTiles(mContext));
+ }
+ };
+
+ public static int getNumQuickTiles(Context context) {
+ return TunerService.get(context).getValue(NUM_QUICK_TILES, 5);
+ }
+
private static class HeaderTileLayout extends LinearLayout implements QSTileLayout {
private final Space mEndSpacer;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 225c10f..5e02428 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -87,6 +87,7 @@
mToolbar.setOnMenuItemClickListener(this);
mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
mContext.getString(com.android.internal.R.string.reset));
+ mToolbar.setTitle(R.string.qs_edit);
mRecyclerView = (RecyclerView) findViewById(android.R.id.list);
mTileAdapter = new TileAdapter(getContext());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index aba9251..d9b3b3f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -25,7 +25,6 @@
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.LayoutInflater;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -277,9 +276,6 @@
return false;
}
}
- if (target.getItemViewType() == TYPE_EDIT && from < mDividerIndex) {
- to++;
- }
move(from, to, mTiles);
mDividerIndex = mTiles.indexOf(null);
notifyItemMoved(from, to);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index aa85f78..d95d3ef 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -28,8 +28,6 @@
import android.os.Handler;
import android.os.Looper;
import android.service.quicksettings.TileService;
-import com.android.systemui.Prefs;
-import com.android.systemui.Prefs.Key;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.QSTile.DrawableIcon;
@@ -57,10 +55,8 @@
}
private void addSystemTiles(QSTileHost host) {
- boolean hasColorMod = Prefs.getBoolean(host.getContext(), Key.QS_NIGHT_ADDED, false)
- && TunerService.isTunerEnabled(host.getContext());
String possible = mContext.getString(R.string.quick_settings_tiles_default)
- + ",hotspot,inversion,saver,work,cast" + (hasColorMod ? ",night" : "");
+ + ",hotspot,inversion,saver,work,cast,night";
String[] possibleTiles = possible.split(",");
final Handler qsHandler = new Handler(host.getLooper());
final Handler mainHandler = new Handler(Looper.getMainLooper());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index 548bffd..2e87525 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -182,6 +182,9 @@
}
private void bindView() {
+ if (mCurrentView == null) {
+ return;
+ }
mDrawable.onBatteryLevelChanged(100, false, false);
mDrawable.onPowerSaveChanged(true);
mDrawable.disableShowPercent();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index d7c12ba..a2934d7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -43,6 +43,7 @@
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
@@ -107,7 +108,7 @@
private RecentsAppWidgetHostView mSearchWidgetHostView;
// Runnables to finish the Recents activity
- private FinishRecentsRunnable mFinishLaunchHomeRunnable;
+ private Intent mHomeIntent;
// The trigger to automatically launch the current task
private int mFocusTimerDuration;
@@ -119,7 +120,7 @@
* last activity launch state. Generally we always launch home when we exit Recents rather than
* just finishing the activity since we don't know what is behind Recents in the task stack.
*/
- class FinishRecentsRunnable implements Runnable {
+ class LaunchHomeRunnable implements Runnable {
Intent mLaunchIntent;
ActivityOptions mOpts;
@@ -127,7 +128,7 @@
/**
* Creates a finish runnable that starts the specified intent.
*/
- public FinishRecentsRunnable(Intent launchIntent, ActivityOptions opts) {
+ public LaunchHomeRunnable(Intent launchIntent, ActivityOptions opts) {
mLaunchIntent = launchIntent;
mOpts = opts;
}
@@ -215,7 +216,7 @@
MetricsLogger.count(this, "overview_trigger_nav_btn", 1);
}
// Keep track of whether we launched from an app or from home
- if (launchState.launchedFromAppWithThumbnail) {
+ if (launchState.launchedFromApp) {
MetricsLogger.count(this, "overview_source_app", 1);
// If from an app, track the stack index of the app in the stack (for affiliated tasks)
MetricsLogger.histogram(this, "overview_source_app_index", launchTaskIndexInStack);
@@ -294,12 +295,8 @@
void dismissRecentsToHome(boolean animateTaskViews, ActivityOptions overrideAnimation) {
DismissRecentsToHomeAnimationStarted dismissEvent =
new DismissRecentsToHomeAnimationStarted(animateTaskViews);
- if (overrideAnimation != null) {
- dismissEvent.addPostAnimationCallback(new FinishRecentsRunnable(
- mFinishLaunchHomeRunnable.mLaunchIntent, overrideAnimation));
- } else {
- dismissEvent.addPostAnimationCallback(mFinishLaunchHomeRunnable);
- }
+ dismissEvent.addPostAnimationCallback(new LaunchHomeRunnable(mHomeIntent,
+ overrideAnimation));
dismissEvent.addPostAnimationCallback(new Runnable() {
@Override
public void run() {
@@ -365,11 +362,10 @@
});
// Create the home intent runnable
- Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
- homeIntent.addCategory(Intent.CATEGORY_HOME);
- homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ mHomeIntent = new Intent(Intent.ACTION_MAIN, null);
+ mHomeIntent.addCategory(Intent.CATEGORY_HOME);
+ mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent, null);
// Bind the search app widget when we first start up
if (RecentsDebugFlags.Static.EnableSearchBar) {
@@ -404,7 +400,7 @@
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
boolean wasLaunchedByAm = !launchState.launchedFromHome &&
- !launchState.launchedFromAppWithThumbnail;
+ !launchState.launchedFromApp;
if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
}
@@ -528,6 +524,7 @@
@Override
public void onMultiWindowChanged(boolean inMultiWindow) {
super.onMultiWindowChanged(inMultiWindow);
+ EventBus.getDefault().send(new ConfigurationChangedEvent());
RecentsTaskLoader loader = Recents.getTaskLoader();
RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
launchOpts.loadIcons = false;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index aa1437b..ec4820a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -28,7 +28,8 @@
public class RecentsActivityLaunchState {
public boolean launchedWithAltTab;
- public boolean launchedFromAppWithThumbnail;
+ public boolean launchedFromApp;
+ public boolean launchedFromAppDocked;
public boolean launchedFromHome;
public boolean launchedFromSearchHome;
public boolean launchedReuseTaskStackViews;
@@ -42,7 +43,8 @@
public void reset() {
launchedFromHome = false;
launchedFromSearchHome = false;
- launchedFromAppWithThumbnail = false;
+ launchedFromApp = false;
+ launchedFromAppDocked = false;
launchedToTaskId = -1;
launchedWithAltTab = false;
launchedHasConfigurationChanged = false;
@@ -67,7 +69,7 @@
public int getInitialFocusTaskIndex(int numTasks) {
RecentsDebugFlags debugFlags = Recents.getDebugFlags();
RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
- if (launchedFromAppWithThumbnail) {
+ if (launchedFromApp) {
if (!launchState.launchedWithAltTab && debugFlags.isFastToggleRecentsEnabled()) {
// If fast toggling, focus the front most task so that the next tap will focus the
// N-1 task
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 9e43bb4..eec0411 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -69,7 +69,6 @@
public final int smallestWidth;
/** Misc **/
- public boolean useHardwareLayers;
public boolean fakeShadows;
public int svelteLevel;
public int searchBarSpaceHeightPx;
@@ -80,7 +79,6 @@
SystemServicesProxy ssp = Recents.getSystemServices();
Context appContext = context.getApplicationContext();
Resources res = appContext.getResources();
- useHardwareLayers = res.getBoolean(R.bool.config_recents_use_hardware_layers);
fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows);
svelteLevel = res.getInteger(R.integer.recents_svelte_level);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index cd64323..6feda81 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -39,8 +39,8 @@
public static final boolean EnableAffiliatedTaskGroups = true;
// Enables the history
public static final boolean EnableHistory = false;
- // Overrides the Tuner flags and enables the fast toggle and timeout
- public static final boolean EnableFastToggleTimeoutOverride = true;
+ // Overrides the Tuner flags and enables the timeout
+ private static final boolean EnableFastToggleTimeout = false;
// Enables us to create mock recents tasks
public static final boolean EnableMockTasks = false;
@@ -54,9 +54,9 @@
public static final int MockTaskGroupsTaskCount = 12;
}
- private static final String KEY_DISABLE_FAST_TOGGLE = "overview_disable_fast_toggle_via_button";
+ private static final String KEY_ENABLE_PAGING = "overview_enable_paging";
- private boolean mDisableFastToggleRecents;
+ private boolean mEnablePaging;
/**
* We read the prefs once when we start the activity, then update them as the tuner changes
@@ -65,31 +65,32 @@
public RecentsDebugFlags(Context context) {
// Register all our flags, this will also call onTuningChanged() for each key, which will
// initialize the current state of each flag
- TunerService.get(context).addTunable(this, KEY_DISABLE_FAST_TOGGLE);
+ TunerService.get(context).addTunable(this, KEY_ENABLE_PAGING);
}
/**
* @return whether we are enabling fast toggling.
*/
public boolean isFastToggleRecentsEnabled() {
- // These checks EnableFastToggleTimeoutOverride
SystemServicesProxy ssp = Recents.getSystemServices();
- if (mDisableFastToggleRecents || ssp.hasFreeformWorkspaceSupport() || ssp.hasDockedTask()
- || ssp.isTouchExplorationEnabled()) {
+ if (ssp.hasFreeformWorkspaceSupport() || ssp.isTouchExplorationEnabled()) {
return false;
}
- if (Static.EnableFastToggleTimeoutOverride) {
- return true;
- }
- return true;
+ return Static.EnableFastToggleTimeout;
+ }
+
+ /**
+ * @return whether we are enabling paging.
+ */
+ public boolean isPagingEnabled() {
+ return mEnablePaging;
}
@Override
public void onTuningChanged(String key, String newValue) {
switch (key) {
- case KEY_DISABLE_FAST_TOGGLE:
- mDisableFastToggleRecents = (newValue != null) &&
- (Integer.parseInt(newValue) != 0);
+ case KEY_ENABLE_PAGING:
+ mEnablePaging = (newValue != null) && (Integer.parseInt(newValue) != 0);
break;
}
EventBus.getDefault().send(new DebugFlagsChangedEvent());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 86b03c8..1458d7b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -16,6 +16,8 @@
package com.android.systemui.recents;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ITaskStackListener;
@@ -64,8 +66,10 @@
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskGrouping;
import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.tv.views.TaskStackHorizontalGridView;
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
import com.android.systemui.recents.views.TaskStackView;
+import com.android.systemui.recents.views.TaskStackViewScroller;
import com.android.systemui.recents.views.TaskViewHeader;
import com.android.systemui.recents.views.TaskViewTransform;
import com.android.systemui.statusbar.BaseStatusBar;
@@ -74,8 +78,6 @@
import java.util.ArrayList;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-
/**
* An implementation of the Recents component for the current user. For secondary users, this can
* be called remotely from the system user.
@@ -98,6 +100,7 @@
//Used to store tv or non-tv activty for use in creating intents.
private final String mRecentsIntentActivityName;
+
/**
* An implementation of ITaskStackListener, that allows us to listen for changes to the system
* task stacks and update recents accordingly.
@@ -276,28 +279,24 @@
mTriggeredFromAltTab = triggeredFromAltTab;
mDraggingInRecents = draggingInRecents;
mLaunchedWhileDocking = launchedWhileDockingTask;
- if (mFastAltTabTrigger.hasTriggered()) {
- // We are calling this from the doze trigger, so just fall through to show Recents
- mFastAltTabTrigger.resetTrigger();
+ if (mFastAltTabTrigger.isAsleep()) {
+ // Fast alt-tab duration has elapsed, fall through to showing Recents and reset
+ mFastAltTabTrigger.stopDozing();
} else if (mFastAltTabTrigger.isDozing()) {
- // We are dozing but haven't yet triggered, ignore this if this is not another alt-tab,
- // otherwise, this is an additional tab (alt-tab*), which means that we should trigger
- // immediately (fall through and disable the pending trigger)
- // TODO: This is tricky, we need to handle the tab key, but Recents has not yet started
- // so we may actually additional signal to handle multiple quick tab cases. The
- // severity of this is inversely proportional to the FAST_ALT_TAB_DELAY_MS
- // duration though
+ // Fast alt-tab duration has not elapsed. If this is triggered by a different
+ // showRecents() call, then ignore that call for now.
+ // TODO: We can not handle quick tabs that happen between the initial showRecents() call
+ // that started the activity and the activity starting up. The severity of this
+ // is inversely proportional to the FAST_ALT_TAB_DELAY_MS duration though.
if (!triggeredFromAltTab) {
return;
}
mFastAltTabTrigger.stopDozing();
- } else {
- // Otherwise, the doze trigger is not running, and if this is an alt tab, we should
- // start the trigger and then wait for the hide (or for it to elapse)
- if (triggeredFromAltTab) {
- mFastAltTabTrigger.startDozing();
- return;
- }
+ } else if (triggeredFromAltTab) {
+ // The fast alt-tab detector is not yet running, so start the trigger and wait for the
+ // hideRecents() call, or for the fast alt-tab duration to elapse
+ mFastAltTabTrigger.startDozing();
+ return;
}
try {
@@ -321,7 +320,6 @@
// Cancel the fast alt-tab trigger
mFastAltTabTrigger.stopDozing();
- mFastAltTabTrigger.resetTrigger();
return;
}
@@ -348,12 +346,14 @@
long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime;
if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) {
+ RecentsDebugFlags debugFlags = Recents.getDebugFlags();
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
if (!launchState.launchedWithAltTab) {
// If the user taps quickly
- if (ViewConfiguration.getDoubleTapMinTime() < elapsedTime &&
- elapsedTime < ViewConfiguration.getDoubleTapTimeout()) {
+ if (!debugFlags.isPagingEnabled() ||
+ (ViewConfiguration.getDoubleTapMinTime() < elapsedTime &&
+ elapsedTime < ViewConfiguration.getDoubleTapTimeout())) {
// Launch the next focused task
EventBus.getDefault().post(new LaunchNextTaskRequestEvent());
} else {
@@ -574,7 +574,7 @@
false /* triggeredFromAltTab */,
dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS,
false /* animate */,
- true /* reloadTasks*/);
+ true /* launchedWhileDockingTask*/);
}
}
@@ -707,8 +707,7 @@
// Update the destination rect
mDummyStackView.updateLayoutForStack(stack);
final Task toTask = new Task();
- final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
- toTask);
+ final TaskViewTransform toTransform = getThumbnailTransitionTransform(stackView, toTask);
ForegroundThread.getHandler().postAtFrontOfQueue(new Runnable() {
@Override
public void run() {
@@ -754,17 +753,20 @@
* Creates the activity options for an app->recents transition.
*/
private ActivityOptions getThumbnailTransitionActivityOptions(
- ActivityManager.RunningTaskInfo topTask, TaskStack stack, TaskStackView stackView) {
+ ActivityManager.RunningTaskInfo topTask, TaskStackView stackView) {
if (topTask.stackId == FREEFORM_WORKSPACE_STACK_ID) {
ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>();
- stackView.getScroller().setStackScrollToInitialState();
- ArrayList<Task> tasks = stack.getStackTasks();
+ ArrayList<Task> tasks = stackView.getStack().getStackTasks();
+ TaskStackLayoutAlgorithm stackLayout = stackView.getStackAlgorithm();
+ TaskStackViewScroller stackScroller = stackView.getScroller();
+
+ stackView.updateToInitialState();
+
for (int i = tasks.size() - 1; i >= 0; i--) {
Task task = tasks.get(i);
if (task.isFreeformTask()) {
- mTmpTransform = stackView.getStackAlgorithm()
- .getStackTransformScreenCoordinates(task,
- stackView.getScroller().getStackScroll(), mTmpTransform, null);
+ mTmpTransform = stackLayout.getStackTransformScreenCoordinates(task,
+ stackScroller.getStackScroll(), mTmpTransform, null);
Rect toTaskRect = new Rect();
mTmpTransform.rect.round(toTaskRect);
Bitmap thumbnail = getThumbnailBitmap(topTask, task, mTmpTransform);
@@ -778,8 +780,7 @@
} else {
// Update the destination rect
Task toTask = new Task();
- TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
- toTask);
+ TaskViewTransform toTransform = getThumbnailTransitionTransform(stackView, toTask);
RectF toTaskRect = toTransform.rect;
Bitmap thumbnail = getThumbnailBitmap(topTask, toTask, toTransform);
if (thumbnail != null) {
@@ -811,9 +812,10 @@
/**
* Returns the transition rect for the given task id.
*/
- private TaskViewTransform getThumbnailTransitionTransform(TaskStack stack,
- TaskStackView stackView, Task runningTaskOut) {
+ private TaskViewTransform getThumbnailTransitionTransform(TaskStackView stackView,
+ Task runningTaskOut) {
// Find the running task in the TaskStack
+ TaskStack stack = stackView.getStack();
Task launchTask = stack.getLaunchTarget();
if (launchTask != null) {
runningTaskOut.copyFrom(launchTask);
@@ -824,7 +826,7 @@
}
// Get the transform for the running task
- stackView.getScroller().setStackScrollToInitialState();
+ stackView.updateToInitialState();
mTmpTransform = stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask,
stackView.getScroller().getStackScroll(), mTmpTransform, null);
return mTmpTransform;
@@ -852,6 +854,7 @@
c.scale(toTransform.scale, toTransform.scale);
mHeaderBar.rebindToTask(toTask, false /* touchExplorationEnabled */,
disabledInSafeMode);
+ mHeaderBar.setDimAlpha(toTransform.dimAlpha);
mHeaderBar.draw(c);
c.setBitmap(null);
}
@@ -900,8 +903,7 @@
if (useThumbnailTransition) {
// Try starting with a thumbnail transition
- ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack,
- mDummyStackView);
+ ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, mDummyStackView);
if (opts != null) {
startRecentsActivity(topTask, opts, false /* fromHome */,
false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
@@ -948,14 +950,15 @@
* Starts the recents activity.
*/
private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
- ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
- TaskStackLayoutAlgorithm.VisibilityReport vr) {
+ ActivityOptions opts, boolean fromHome, boolean fromSearchHome,
+ boolean fromThumbnail, TaskStackLayoutAlgorithm.VisibilityReport vr) {
// Update the configuration based on the launch options
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
launchState.launchedFromHome = fromSearchHome || fromHome;
launchState.launchedFromSearchHome = fromSearchHome;
- launchState.launchedFromAppWithThumbnail = fromThumbnail;
+ launchState.launchedFromApp = fromThumbnail || mLaunchedWhileDocking;
+ launchState.launchedFromAppDocked = mLaunchedWhileDocking;
launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
launchState.launchedWithAltTab = mTriggeredFromAltTab;
launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
diff --git a/core/java/android/hardware/camera2/utils/LongParcelable.aidl b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
similarity index 62%
rename from core/java/android/hardware/camera2/utils/LongParcelable.aidl
rename to packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
index 98ad1b2..0ad4681 100644
--- a/core/java/android/hardware/camera2/utils/LongParcelable.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -14,7 +14,13 @@
* limitations under the License.
*/
-package android.hardware.camera2.utils;
+package com.android.systemui.recents.events.activity;
-/** @hide */
-parcelable LongParcelable;
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent when the Recents activity configuration has changed.
+ */
+public class ConfigurationChangedEvent extends EventBus.AnimatedEvent {
+ // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTvTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTvTaskEvent.java
new file mode 100644
index 0000000..04ca68f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTvTaskEvent.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.recents.events.activity;
+
+
+import android.graphics.Rect;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.tv.views.TaskCardView;
+
+public class LaunchTvTaskEvent extends EventBus.Event {
+
+ public final TaskCardView taskView;
+ public final Task task;
+ public final Rect targetTaskBounds;
+ public final int targetTaskStack;
+
+ public LaunchTvTaskEvent(TaskCardView taskView, Task task, Rect targetTaskBounds,
+ int targetTaskStack) {
+ this.taskView = taskView;
+ this.task = task;
+ this.targetTaskBounds = targetTaskBounds;
+ this.targetTaskStack = targetTaskStack;
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTvTaskStartedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTvTaskStartedEvent.java
new file mode 100644
index 0000000..75d3efa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTvTaskStartedEvent.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.tv.views.TaskCardView;
+
+/**
+ * This event is sent following {@link LaunchTvTaskEvent} after the call to the system is made to
+ * start the task, only used on TV.
+ */
+public class LaunchTvTaskStartedEvent extends EventBus.AnimatedEvent {
+
+ public final TaskCardView taskView;
+
+ public LaunchTvTaskStartedEvent(TaskCardView taskView) {
+ this.taskView = taskView;
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
index 95aa10f..574ea03 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
@@ -30,7 +30,7 @@
@ViewDebug.ExportedProperty(category="recents")
boolean mIsDozing;
@ViewDebug.ExportedProperty(category="recents")
- boolean mHasTriggered;
+ boolean mIsAsleep;
@ViewDebug.ExportedProperty(category="recents")
int mDozeDurationMilliseconds;
Runnable mOnSleepRunnable;
@@ -40,7 +40,7 @@
@Override
public void run() {
mIsDozing = false;
- mHasTriggered = true;
+ mIsAsleep = true;
mOnSleepRunnable.run();
}
};
@@ -56,7 +56,7 @@
*/
public void startDozing() {
forcePoke();
- mHasTriggered = false;
+ mIsAsleep = false;
}
/**
@@ -65,6 +65,7 @@
public void stopDozing() {
mHandler.removeCallbacks(mDozeRunnable);
mIsDozing = false;
+ mIsAsleep = false;
}
/**
@@ -99,12 +100,7 @@
}
/** Returns whether the trigger has fired at least once. */
- public boolean hasTriggered() {
- return mHasTriggered;
- }
-
- /** Resets the doze trigger state. */
- public void resetTrigger() {
- mHasTriggered = false;
+ public boolean isAsleep() {
+ return mIsAsleep;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 7c5a931..532e796 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -695,6 +695,37 @@
}
/**
+ * Returns a banner used on TV for the specified Activity.
+ */
+ public Drawable getActivityBanner(ActivityInfo info) {
+ if (mPm == null) return null;
+
+ // If we are mocking, then return a mock banner
+ if (RecentsDebugFlags.Static.EnableMockTasks) {
+ return new ColorDrawable(0xFF666666);
+ }
+
+ Drawable banner = info.loadBanner(mPm);
+ return banner;
+ }
+
+ /**
+ * Returns a logo used on TV for the specified Activity.
+ */
+ public Drawable getActivityLogo(ActivityInfo info) {
+ if (mPm == null) return null;
+
+ // If we are mocking, then return a mock logo
+ if (RecentsDebugFlags.Static.EnableMockTasks) {
+ return new ColorDrawable(0xFF666666);
+ }
+
+ Drawable logo = info.loadLogo(mPm);
+ return logo;
+ }
+
+
+ /**
* Returns the given label for a user, badging if necessary.
*/
private String getBadgedLabel(String label, int userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index 0c48cf7..02c8d96 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -40,7 +40,6 @@
import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
-import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
@@ -60,6 +59,8 @@
import com.android.systemui.tv.pip.PipManager;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
* The main TV recents activity started by the RecentsImpl.
@@ -157,11 +158,13 @@
mRecentsView.setTaskStack(stack);
+ List stackTasks = stack.getStackTasks();
+ Collections.reverse(stackTasks);
if (mTaskStackViewAdapter == null) {
- mTaskStackViewAdapter = new TaskStackHorizontalViewAdapter(stack.getStackTasks());
+ mTaskStackViewAdapter = new TaskStackHorizontalViewAdapter(stackTasks);
mRecentsView.setTaskStackViewAdapter(mTaskStackViewAdapter);
} else {
- mTaskStackViewAdapter.setNewStackTasks(stack.getStackTasks());
+ mTaskStackViewAdapter.setNewStackTasks(stackTasks);
}
if (launchState.launchedToTaskId != -1) {
@@ -284,7 +287,7 @@
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
boolean wasLaunchedByAm = !launchState.launchedFromHome &&
- !launchState.launchedFromAppWithThumbnail;
+ !launchState.launchedFromApp;
if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
new file mode 100644
index 0000000..ef8d48e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.recents.tv.views;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IRemoteCallback;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.WindowManagerGlobal;
+import com.android.internal.annotations.GuardedBy;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.*;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+
+
+public class RecentsTvTransitionHelper {
+ private static final String TAG = "RecentsTvTransitionHelper";
+
+ private Context mContext;
+ private Handler mHandler;
+
+ public RecentsTvTransitionHelper(Context context, Handler handler) {
+ mContext = context;
+ mHandler = handler;
+ }
+
+ public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
+ final TaskStackHorizontalGridView stackView, final TaskCardView taskView,
+ final Rect bounds, int destinationStack) {
+ final ActivityOptions opts = ActivityOptions.makeBasic();
+ if (bounds != null) {
+ opts.setLaunchBounds(bounds.isEmpty() ? null : bounds);
+ }
+
+ final ActivityOptions.OnAnimationStartedListener animStartedListener;
+ if (task.thumbnail != null && task.thumbnail.getWidth() > 0 &&
+ task.thumbnail.getHeight() > 0) {
+ animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
+ @Override
+ public void onAnimationStarted() {
+ // If we are launching into another task, cancel the previous task's
+ // window transition
+ EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
+ EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
+ }
+ };
+ } else {
+ // This is only the case if the task is not on screen (scrolled offscreen for example)
+ animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
+ @Override
+ public void onAnimationStarted() {
+ EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
+ }
+ };
+ }
+
+ if (taskView == null) {
+ // If there is no task view, then we do not need to worry about animating out occluding
+ // task views, and we can launch immediately
+ startTaskActivity(stack, task, taskView, opts, animStartedListener);
+ } else {
+ LaunchTvTaskStartedEvent launchStartedEvent = new LaunchTvTaskStartedEvent(taskView);
+ EventBus.getDefault().send(launchStartedEvent);
+ startTaskActivity(stack, task, taskView, opts, animStartedListener);
+ }
+ }
+
+ private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskCardView taskView,
+ ActivityOptions opts,final ActivityOptions.OnAnimationStartedListener animStartedListener) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.startActivityFromRecents(mContext, task.key.id, task.title, opts)) {
+ // Keep track of the index of the task launch
+ int taskIndexFromFront = 0;
+ int taskIndex = stack.indexOfStackTask(task);
+ if (taskIndex > -1) {
+ taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
+ }
+ EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront));
+ } else {
+ // Keep track of failed launches
+ EventBus.getDefault().send(new LaunchTaskFailedEvent());
+ }
+
+ IRemoteCallback.Stub callback = null;
+ if (animStartedListener != null) {
+ callback = new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (animStartedListener != null) {
+ animStartedListener.onAnimationStarted();
+ }
+ }
+ });
+ }
+ };
+ }
+ try {
+ Rect taskRect = taskView.getGlobalRect();
+ WindowManagerGlobal.getWindowManagerService()
+ .overridePendingAppTransitionThumb(task.thumbnail, taskRect.left,
+ taskRect.top, callback, true);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to override transition: " + e);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
index 8e768a2..bf6229c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
@@ -17,6 +17,7 @@
import android.content.Context;
import android.graphics.Rect;
+import android.os.Handler;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -31,7 +32,7 @@
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
-import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
+import com.android.systemui.recents.events.activity.LaunchTvTaskEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.Task;
@@ -53,7 +54,8 @@
private View mEmptyView;
private boolean mAwaitingFirstLayout = true;
private Rect mSystemInsets = new Rect();
-
+ private RecentsTvTransitionHelper mTransitionHelper;
+ private Handler mHandler;
public RecentsTvView(Context context) {
this(context, null);
@@ -75,6 +77,8 @@
LayoutInflater inflater = LayoutInflater.from(context);
mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
addView(mEmptyView);
+ mHandler = new Handler();
+ mTransitionHelper = new RecentsTvTransitionHelper(mContext, mHandler);
}
public void setTaskStack(TaskStack stack) {
@@ -209,6 +213,11 @@
/**** EventBus Events ****/
+ public final void onBusEvent(LaunchTvTaskEvent event) {
+ mTransitionHelper.launchTaskFromRecents(mStack, event.task, mTaskStackHorizontalView,
+ event.taskView, event.targetTaskBounds, event.targetTaskStack);
+ }
+
public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
// If we are going home, cancel the previous task's window transition
EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
index e275f22..7d8a3ce 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
@@ -16,20 +16,20 @@
package com.android.systemui.recents.tv.views;
import android.content.Context;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.ImageView;
-import android.widget.RelativeLayout;
+import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.systemui.R;
-import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.tv.animations.ViewFocusAnimator;
+import com.android.systemui.recents.model.Task;
-public class TaskCardView extends RelativeLayout {
+public class TaskCardView extends LinearLayout {
private ImageView mThumbnailView;
private TextView mTitleTextView;
- private TextView mContentTextView;
private ImageView mBadgeView;
private Task mTask;
@@ -52,7 +52,6 @@
protected void onFinishInflate() {
mThumbnailView = (ImageView) findViewById(R.id.card_view_thumbnail);
mTitleTextView = (TextView) findViewById(R.id.card_title_text);
- mContentTextView = (TextView) findViewById(R.id.card_content_text);
mBadgeView = (ImageView) findViewById(R.id.card_extra_badge);
}
@@ -60,11 +59,27 @@
mTask = task;
mThumbnailView.setImageBitmap(task.thumbnail);
mTitleTextView.setText(task.title);
- mContentTextView.setText(task.contentDescription);
mBadgeView.setImageDrawable(task.icon);
}
public Task getTask() {
return mTask;
}
+
+ @Override
+ public void getFocusedRect(Rect r) {
+ mThumbnailView.getFocusedRect(r);
+ }
+
+ public Rect getFocusedRect() {
+ Rect r = new Rect();
+ getFocusedRect(r);
+ return r;
+ }
+
+ public Rect getGlobalRect() {
+ Rect r = new Rect();
+ getGlobalVisibleRect(r);
+ return r;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
index 58ec852..4458639 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
@@ -15,7 +15,6 @@
*/
package com.android.systemui.recents.tv.views;
-
import android.content.Context;
import android.support.v17.leanback.widget.HorizontalGridView;
import android.util.AttributeSet;
@@ -36,13 +35,17 @@
/**
* Horizontal Grid View Implementation to show the Task Stack for TV.
*/
-public class TaskStackHorizontalGridView extends HorizontalGridView implements TaskStackCallbacks{
+public class TaskStackHorizontalGridView extends HorizontalGridView implements TaskStackCallbacks {
private TaskStack mStack;
private ArrayList<TaskCardView> mTaskViews = new ArrayList<>();
private Task mFocusedTask;
+ public TaskStackHorizontalGridView(Context context) {
+ this(context, null);
+ }
+
public TaskStackHorizontalGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -64,8 +67,6 @@
* Resets this view for reuse.
*/
public void reset() {
- // Reset the focused task
- resetFocusedTask(getFocusedTask());
requestLayout();
}
@@ -73,12 +74,6 @@
* @param task - Task to reset
*/
private void resetFocusedTask(Task task) {
- if (task != null) {
- TaskCardView tv = getChildViewForTask(task);
- if (tv != null) {
- tv.requestFocus();
- }
- }
mFocusedTask = null;
}
@@ -107,6 +102,9 @@
* @return - The focused task.
*/
public Task getFocusedTask() {
+ if (findFocus() != null) {
+ mFocusedTask = ((TaskCardView)findFocus()).getTask();
+ }
return mFocusedTask;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
index f154331..fba424e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
@@ -16,7 +16,6 @@
package com.android.systemui.recents.tv.views;
import android.app.Activity;
-import android.app.ActivityManagerNative;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
@@ -24,15 +23,20 @@
import android.view.ViewGroup;
import com.android.systemui.R;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.LaunchTvTaskEvent;
import com.android.systemui.recents.model.Task;
import java.util.ArrayList;
import java.util.List;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
public class TaskStackHorizontalViewAdapter extends
RecyclerView.Adapter<TaskStackHorizontalViewAdapter.ViewHolder> {
- private static final String TAG = "TaskStackHorizontalViewAdapter";
+ //Full class name is 30 characters
+ private static final String TAG = "TaskStackViewAdapter";
private List<Task> mTaskList;
static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
@@ -54,7 +58,8 @@
@Override
public void onClick(View v) {
try {
- ActivityManagerNative.getDefault().startActivityFromRecents(mTask.key.id, null);
+ EventBus.getDefault().send(new LaunchTvTaskEvent(mTaskCardView, mTask,
+ null, INVALID_STACK_ID));
((Activity)(v.getContext())).finish();
} catch (Exception e) {
Log.e(TAG, v.getContext()
@@ -73,11 +78,12 @@
mTaskList.addAll(tasks);
notifyDataSetChanged();
}
+
@Override
public TaskStackHorizontalViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(parent.getContext())
- .inflate(R.layout.recents_task_card_view, parent, false);
+ .inflate(R.layout.recents_tv_task_card_view, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
index 4359101..72b914c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
@@ -37,6 +37,13 @@
private int mTaskPadding;
public FreeformWorkspaceLayoutAlgorithm(Context context) {
+ reloadOnConfigurationChange(context);
+ }
+
+ /**
+ * Reloads the layout for the current configuration.
+ */
+ public void reloadOnConfigurationChange(Context context) {
// This is applied to the edges of each task
mTaskPadding = context.getResources().getDimensionPixelSize(
R.dimen.recents_freeform_workspace_task_padding) / 2;
@@ -72,8 +79,7 @@
}
// Bound the task width to the workspace width so that at the worst case, it will
// fit its own row
- normalizedTaskWidths[i] = Math.min(rowTaskWidth,
- normalizedWorkspaceWidth);
+ normalizedTaskWidths[i] = Math.min(rowTaskWidth, normalizedWorkspaceWidth);
}
// Determine the scale to best fit each of the tasks in the workspace
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index 37b2859..e5022a4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -105,9 +105,6 @@
animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
@Override
public void onAnimationStarted() {
- // If we are launching into another task, cancel the previous task's
- // window transition
- EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
if (screenPinningRequested) {
@@ -149,6 +146,10 @@
animStartedListener);
}
}
+
+ // If we are launching into another task, cancel the previous task's
+ // window transition
+ EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 5dde926..10f491e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -192,7 +192,7 @@
// If we are already occluded by the app, then just set the default background scrim now.
// Otherwise, defer until the enter animation completes to animate the scrim with the
// tasks for the home animation.
- if (launchState.launchedWhileDocking || launchState.launchedFromAppWithThumbnail
+ if (launchState.launchedWhileDocking || launchState.launchedFromApp
|| mStack.getTaskCount() == 0) {
mBackgroundScrim.setAlpha((int) (DEFAULT_SCRIM_ALPHA * 255));
} else {
@@ -671,7 +671,7 @@
public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
- if (!launchState.launchedWhileDocking && !launchState.launchedFromAppWithThumbnail
+ if (!launchState.launchedWhileDocking && !launchState.launchedFromApp
&& mStack.getTaskCount() > 0) {
animateBackgroundScrim(DEFAULT_SCRIM_ALPHA,
TaskStackAnimationHelper.ENTER_FROM_HOME_TRANSLATION_DURATION);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index d152010..758f4d8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -56,8 +56,8 @@
/**
* Callback to start the animation for the launch target {@link TaskView}.
*/
- void onStartLaunchTargetEnterAnimation(int duration, boolean screenPinningEnabled,
- ReferenceCountedTrigger postAnimationTrigger);
+ void onStartLaunchTargetEnterAnimation(TaskViewTransform transform, int duration,
+ boolean screenPinningEnabled, ReferenceCountedTrigger postAnimationTrigger);
/**
* Callback to start the animation for the launch target {@link TaskView} when it is
@@ -141,7 +141,7 @@
tv.setVisibility(View.INVISIBLE);
} else if (launchState.launchedHasConfigurationChanged) {
// Just load the views as-is
- } else if (launchState.launchedFromAppWithThumbnail) {
+ } else if (launchState.launchedFromApp) {
if (task.isLaunchTarget) {
tv.onPrepareLaunchTargetForEnterAnimation();
} else if (currentTaskOccludesLaunchTarget) {
@@ -205,10 +205,11 @@
stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
null);
- if (launchState.launchedFromAppWithThumbnail) {
+ if (launchState.launchedFromApp) {
if (task.isLaunchTarget) {
- tv.onStartLaunchTargetEnterAnimation(taskViewEnterFromAppDuration,
- mStackView.mScreenPinningEnabled, postAnimationTrigger);
+ tv.onStartLaunchTargetEnterAnimation(mTmpTransform,
+ taskViewEnterFromAppDuration, mStackView.mScreenPinningEnabled,
+ postAnimationTrigger);
} else {
// Animate the task up if it was occluding the launch target
if (currentTaskOccludesLaunchTarget) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 261b6f6..17c3eeb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -29,6 +29,7 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.misc.FreePathInterpolator;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
@@ -36,6 +37,7 @@
import com.android.systemui.recents.model.TaskStack;
import java.util.ArrayList;
+import java.util.List;
/**
* Used to describe a visible range that can be normalized to [0, 1].
@@ -220,6 +222,10 @@
private Range mUnfocusedRange;
private Range mFocusedRange;
+ // The initial offset from the top of the stack
+ @ViewDebug.ExportedProperty(category="recents")
+ private int mInitialTopPeekHeight;
+
// The offset from the top when scrolled to the top of the stack
@ViewDebug.ExportedProperty(category="recents")
private int mFocusedTopPeekHeight;
@@ -231,6 +237,10 @@
@ViewDebug.ExportedProperty(category="recents")
private int mStackTopOffset;
+ // The height of the header bar
+ @ViewDebug.ExportedProperty(category="recents")
+ private int mHeaderBarHeight;
+
// The offset from the bottom of the stack to the bottom of the bounds when the stack is
// scrolled to the front
@ViewDebug.ExportedProperty(category="recents")
@@ -249,6 +259,9 @@
private FreePathInterpolator mUnfocusedDimCurveInterpolator;
private FreePathInterpolator mFocusedDimCurveInterpolator;
+ // Indexed from the front of the stack, the normalized x in the unfocused range for each task
+ private float[] mInitialNormX;
+
// The state of the stack focus (0..1), which controls the transition of the stack from the
// focused to non-focused state
@ViewDebug.ExportedProperty(category="recents")
@@ -292,23 +305,32 @@
TaskViewTransform mFrontOfStackTransform = new TaskViewTransform();
public TaskStackLayoutAlgorithm(Context context, TaskStackLayoutAlgorithmCallbacks cb) {
- Resources res = context.getResources();
mContext = context;
mCb = cb;
+ mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm(context);
+ reloadOnConfigurationChange(context);
+ }
+ /**
+ * Reloads the layout for the current configuration.
+ */
+ public void reloadOnConfigurationChange(Context context) {
+ Resources res = context.getResources();
mFocusedRange = new Range(res.getFloat(R.integer.recents_layout_focused_range_min),
res.getFloat(R.integer.recents_layout_focused_range_max));
mUnfocusedRange = new Range(res.getFloat(R.integer.recents_layout_unfocused_range_min),
res.getFloat(R.integer.recents_layout_unfocused_range_max));
- mFocusState = getDefaultFocusState();
+ mFocusState = getInitialFocusState();
+ mInitialTopPeekHeight = res.getDimensionPixelSize(R.dimen.recents_initial_top_peek_size);
mFocusedTopPeekHeight =
res.getDimensionPixelSize(R.dimen.recents_layout_focused_top_peek_size);
mFocusedBottomTaskPeekHeight =
res.getDimensionPixelSize(R.dimen.recents_layout_focused_bottom_task_peek_size);
+ mHeaderBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
- mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm(context);
+ mFreeformLayoutAlgorithm.reloadOnConfigurationChange(context);
}
/**
@@ -316,7 +338,7 @@
*/
public void reset() {
mTaskIndexOverrideMap.clear();
- setFocusState(getDefaultFocusState());
+ setFocusState(getInitialFocusState());
}
/**
@@ -439,46 +461,87 @@
mTaskIndexMap.put(task.key.id, i);
}
- // Calculate the min/max scroll
- if (getDefaultFocusState() > 0f) {
- mMinScrollP = 0;
- mMaxScrollP = Math.max(mMinScrollP, mNumStackTasks - 1);
- } else {
- if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
- mMinScrollP = mMaxScrollP = 0;
- } else {
- float bottomOffsetPct = (float) (mStackBottomOffset + mTaskRect.height()) /
- mStackRect.height();
- float normX = mUnfocusedCurveInterpolator.getX(bottomOffsetPct);
- mMinScrollP = 0;
- mMaxScrollP = Math.max(mMinScrollP, (mNumStackTasks - 1) -
- Math.max(0, mUnfocusedRange.getAbsoluteX(normX)));
- }
- }
-
+ // Update the freeform tasks
if (!freeformTasks.isEmpty()) {
mFreeformLayoutAlgorithm.update(freeformTasks, this);
- mInitialScrollP = mMaxScrollP;
- } else {
- Task launchTask = stack.getLaunchTarget();
- int launchTaskIndex = launchTask != null
- ? stack.indexOfStackTask(launchTask)
- : mNumStackTasks - 1;
- if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
- mInitialScrollP = mMinScrollP;
- } else if (getDefaultFocusState() > 0f) {
- if (launchState.launchedFromHome) {
- mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
- } else {
- mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP,
- mMaxScrollP);
- }
+ }
+
+ // Calculate the min/max/initial scroll
+ Task launchTask = stack.getLaunchTarget();
+ int launchTaskIndex = launchTask != null
+ ? stack.indexOfStackTask(launchTask)
+ : mNumStackTasks - 1;
+ if (getInitialFocusState() == STATE_FOCUSED) {
+ mMinScrollP = 0;
+ mMaxScrollP = Math.max(mMinScrollP, mNumStackTasks - 1);
+ if (launchState.launchedFromHome) {
+ mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
} else {
- float offsetPct = (float) (mTaskRect.height() / 3) / mStackRect.height();
- float normX = mUnfocusedCurveInterpolator.getX(offsetPct);
- mInitialScrollP = Utilities.clamp(launchTaskIndex -
- mUnfocusedRange.getAbsoluteX(normX), mMinScrollP, mMaxScrollP);
+ mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP, mMaxScrollP);
}
+ } else if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
+ // If there is one stack task, ignore the min/max/initial scroll positions
+ mMinScrollP = 0;
+ mMaxScrollP = 0;
+ mInitialScrollP = 0;
+ } else {
+ // Set the max scroll to be the point where the front most task is visible with the
+ // stack bottom offset
+ int maxBottomOffset = mStackBottomOffset + mTaskRect.height();
+ float maxBottomOffsetPct = (float) maxBottomOffset / mStackRect.height();
+ float maxBottomNormX = mUnfocusedCurveInterpolator.getX(maxBottomOffsetPct);
+ mUnfocusedRange.offset(0f);
+ mMinScrollP = 0;
+ mMaxScrollP = Math.max(mMinScrollP, (mNumStackTasks - 1) -
+ Math.max(0, mUnfocusedRange.getAbsoluteX(maxBottomNormX)));
+ boolean scrollToFront = launchState.launchedFromHome ||
+ launchState.launchedFromAppDocked;
+ if (scrollToFront) {
+ mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
+ } else {
+ mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP, mMaxScrollP);
+ }
+
+ // Set the initial scroll to the predefined state (which differs from the stack)
+ int initialPeekOffset = mStackRect.height() - mInitialTopPeekHeight;
+ float initialPeekOffsetPct = (float) initialPeekOffset / mStackRect.height();
+ float initialPeekOffsetNormX = mUnfocusedCurveInterpolator.getX(initialPeekOffsetPct);
+ float initialFocusedOffset = mStackRect.height() - mInitialTopPeekHeight -
+ (mHeaderBarHeight * 1f) + 1;
+ float initialFocusedOffsetPct = (float) initialFocusedOffset / mStackRect.height();
+ float initialFocusedNormX = mUnfocusedCurveInterpolator.getX(initialFocusedOffsetPct);
+ int initialBottomOffset = mStackBottomOffset + mHeaderBarHeight;
+ float initialBottomOffsetPct = (float) initialBottomOffset / mStackRect.height();
+ float initialBottomNormX = mUnfocusedCurveInterpolator.getX(initialBottomOffsetPct);
+ /*
+ // If we want to offset the top card slightly
+ mInitialNormX = scrollToFront
+ ? new float[] { initialFocusedNormX, initialPeekOffsetNormX, 0f }
+ : new float[] { initialBottomNormX, initialFocusedNormX,
+ initialPeekOffsetNormX, 0f };
+ */
+ mInitialNormX = scrollToFront
+ ? new float[] { initialFocusedNormX, initialPeekOffsetNormX, 0f }
+ : new float[] { initialBottomNormX, 0.5f, 0f };
+ }
+ }
+
+ public void updateToInitialState(List<Task> tasks) {
+ if (mInitialNormX == null) {
+ return;
+ }
+
+ RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+ mUnfocusedRange.offset(0f);
+ int taskCount = tasks.size();
+ for (int i = taskCount - 1; i >= 0; i--) {
+ int indexFromFront = taskCount - i - 1;
+ if (indexFromFront >= mInitialNormX.length) {
+ break;
+ }
+ float newTaskProgress = mInitialScrollP +
+ mUnfocusedRange.getAbsoluteX(mInitialNormX[indexFromFront]);
+ mTaskIndexOverrideMap.put(tasks.get(i).key.id, newTaskProgress);
}
}
@@ -500,6 +563,10 @@
}
}
+ public void clearUnfocusedTaskOverrides() {
+ mTaskIndexOverrideMap.clear();
+ }
+
/**
* Updates this stack when a scroll happens.
*/
@@ -523,7 +590,7 @@
} else {
// Scrolling override x away from x, we should still move the scroll towards x
float deltaX = overrideX - x;
- newOverrideX = Math.signum(deltaX) * (Math.abs(deltaX) - deltaScroll);
+ newOverrideX = Math.signum(deltaX) * (Math.abs(deltaX) - Math.abs(deltaScroll));
mTaskIndexOverrideMap.put(taskId, x + newOverrideX);
}
}
@@ -532,8 +599,13 @@
/**
* Returns the default focus state.
*/
- public int getDefaultFocusState() {
- return STATE_FOCUSED;
+ public int getInitialFocusState() {
+ RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+ if (debugFlags.isPagingEnabled()) {
+ return STATE_FOCUSED;
+ } else {
+ return STATE_UNFOCUSED;
+ }
}
/**
@@ -577,7 +649,7 @@
// Otherwise, walk backwards in the stack and count the number of tasks and visible
// thumbnails and add that to the total freeform task count
TaskViewTransform tmpTransform = new TaskViewTransform();
- Range currentRange = getDefaultFocusState() > 0f ? mFocusedRange : mUnfocusedRange;
+ Range currentRange = getInitialFocusState() > 0f ? mFocusedRange : mUnfocusedRange;
currentRange.offset(mInitialScrollP);
int taskBarHeight = mContext.getResources().getDimensionPixelSize(
R.dimen.recents_task_bar_height);
@@ -600,8 +672,9 @@
boolean isFrontMostTaskInGroup = task.group == null || task.group.isFrontMostTask(task);
if (isFrontMostTaskInGroup) {
- getStackTransform(taskProgress, mInitialScrollP, mFocusState, tmpTransform, null,
- false /* ignoreSingleTaskCase */, false /* forceUpdate */);
+ getStackTransform(taskProgress, taskProgress, mInitialScrollP, mFocusState,
+ tmpTransform, null, false /* ignoreSingleTaskCase */,
+ false /* forceUpdate */);
float screenY = tmpTransform.rect.top;
boolean hasVisibleThumbnail = (prevScreenY - screenY) > taskBarHeight;
if (hasVisibleThumbnail) {
@@ -635,23 +708,34 @@
public TaskViewTransform getStackTransform(Task task, float stackScroll,
TaskViewTransform transformOut, TaskViewTransform frontTransform) {
return getStackTransform(task, stackScroll, mFocusState, transformOut, frontTransform,
- false /* forceUpdate */);
+ false /* forceUpdate */, false /* ignoreTaskOverrides */);
+ }
+
+ public TaskViewTransform getStackTransform(Task task, float stackScroll,
+ TaskViewTransform transformOut, TaskViewTransform frontTransform,
+ boolean ignoreTaskOverrides) {
+ return getStackTransform(task, stackScroll, mFocusState, transformOut, frontTransform,
+ false /* forceUpdate */, ignoreTaskOverrides);
}
public TaskViewTransform getStackTransform(Task task, float stackScroll, int focusState,
- TaskViewTransform transformOut, TaskViewTransform frontTransform, boolean forceUpdate) {
+ TaskViewTransform transformOut, TaskViewTransform frontTransform, boolean forceUpdate,
+ boolean ignoreTaskOverrides) {
if (mFreeformLayoutAlgorithm.isTransformAvailable(task, this)) {
mFreeformLayoutAlgorithm.getTransform(task, transformOut, this);
return transformOut;
} else {
// Return early if we have an invalid index
- if (task == null || mTaskIndexMap.get(task.key.id, -1) == -1) {
+ int nonOverrideTaskProgress = mTaskIndexMap.get(task.key.id, -1);
+ if (task == null || nonOverrideTaskProgress == -1) {
transformOut.reset();
return transformOut;
}
- float taskProgress = getStackScrollForTask(task);
- getStackTransform(taskProgress, stackScroll, focusState, transformOut,
- frontTransform, false /* ignoreSingleTaskCase */, forceUpdate);
+ float taskProgress = ignoreTaskOverrides
+ ? nonOverrideTaskProgress
+ : getStackScrollForTask(task);
+ getStackTransform(taskProgress, nonOverrideTaskProgress, stackScroll, focusState,
+ transformOut, frontTransform, false /* ignoreSingleTaskCase */, forceUpdate);
return transformOut;
}
}
@@ -676,9 +760,9 @@
* internally to ensure that we can calculate the transform for any
* position in the stack.
*/
- public void getStackTransform(float taskProgress, float stackScroll, int focusState,
- TaskViewTransform transformOut, TaskViewTransform frontTransform,
- boolean ignoreSingleTaskCase, boolean forceUpdate) {
+ public void getStackTransform(float taskProgress, float nonOverrideTaskProgress,
+ float stackScroll, int focusState, TaskViewTransform transformOut,
+ TaskViewTransform frontTransform, boolean ignoreSingleTaskCase, boolean forceUpdate) {
SystemServicesProxy ssp = Recents.getSystemServices();
// Compute the focused and unfocused offset
@@ -687,6 +771,8 @@
mFocusedRange.offset(boundedStackScroll);
float boundedScrollUnfocusedRangeX = mUnfocusedRange.getNormalizedX(taskProgress);
float boundedScrollFocusedRangeX = mFocusedRange.getNormalizedX(taskProgress);
+ float boundedScrollUnfocusedNonOverrideRangeX =
+ mUnfocusedRange.getNormalizedX(nonOverrideTaskProgress);
mUnfocusedRange.offset(stackScroll);
mFocusedRange.offset(stackScroll);
boolean unfocusedVisible = mUnfocusedRange.isInRange(taskProgress);
@@ -730,7 +816,7 @@
y = (mStackRect.top - mTaskRect.top) +
(int) Utilities.mapRange(focusState, unfocusedY, focusedY);
- z = Utilities.mapRange(Utilities.clamp01(boundedScrollUnfocusedRangeX),
+ z = Utilities.mapRange(Utilities.clamp01(boundedScrollUnfocusedNonOverrideRangeX),
mMinTranslationZ, mMaxTranslationZ);
dimAlpha = Utilities.mapRange(focusState, unfocusedDim, focusedDim);
viewOutlineAlpha = Utilities.mapRange(Utilities.clamp01(boundedScrollUnfocusedRangeX),
@@ -851,8 +937,8 @@
// The unfocused dim interpolator starts at max dim, reduces to zero at 0.5 (the focused
// task), then goes back to max dim towards the front of the stack
p.moveTo(0f, MAX_DIM);
- p.cubicTo(0f, 0.1f, 0.4f, 0f, 0.5f, 0f);
- p.cubicTo(0.6f, 0f, 0.9f, MAX_DIM - 0.1f, 1f, MAX_DIM / 2f);
+ p.cubicTo(0.1f, MAX_DIM, 0.4f, 0.0f, 0.5f, 0f);
+ p.cubicTo(0.6f, 0f, 0.9f, MAX_DIM / 2f, 1f, MAX_DIM / 2f);
return p;
}
@@ -870,9 +956,9 @@
mFocusedRange.relativeMin);
float max = Utilities.mapRange(mFocusState, mUnfocusedRange.relativeMax,
mFocusedRange.relativeMax);
- getStackTransform(min, 0f, mFocusState, mBackOfStackTransform, null,
+ getStackTransform(min, min, 0f, mFocusState, mBackOfStackTransform, null,
true /* ignoreSingleTaskCase */, true /* forceUpdate */);
- getStackTransform(max, 0f, mFocusState, mFrontOfStackTransform, null,
+ getStackTransform(max, max, 0f, mFocusState, mFrontOfStackTransform, null,
true /* ignoreSingleTaskCase */, true /* forceUpdate */);
mBackOfStackTransform.visible = true;
mFrontOfStackTransform.visible = true;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index e1a81c8..c2bfc28 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -35,7 +35,6 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.MutableBoolean;
-import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -56,6 +55,7 @@
import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
import com.android.systemui.recents.events.activity.EnterRecentsTaskStackAnimationCompletedEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
@@ -73,7 +73,6 @@
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
-import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
import com.android.systemui.recents.events.ui.UserInteractionEvent;
@@ -274,10 +273,18 @@
}
/** Returns the task stack. */
- TaskStack getStack() {
+ public TaskStack getStack() {
return mStack;
}
+ /**
+ * Updates this TaskStackView to the initial state.
+ */
+ public void updateToInitialState() {
+ mStackScroller.setStackScrollToInitialState();
+ mLayoutAlgorithm.updateToInitialState(mStack.getStackTasks());
+ }
+
/** Updates the list of task views */
void updateTaskViewsList() {
mTaskViews.clear();
@@ -355,7 +362,6 @@
mAwaitingFirstLayout = true;
mEnterAnimationComplete = false;
mUIDozeTrigger.stopDozing();
- mUIDozeTrigger.resetTrigger();
mStackScroller.reset();
mLayoutAlgorithm.reset();
readSystemFlags();
@@ -410,7 +416,7 @@
*/
int[] computeVisibleTaskTransforms(ArrayList<TaskViewTransform> taskTransforms,
ArrayList<Task> tasks, float curStackScroll, float targetStackScroll,
- ArraySet<Task.TaskKey> ignoreTasksSet) {
+ ArraySet<Task.TaskKey> ignoreTasksSet, boolean ignoreTaskOverrides) {
int taskCount = tasks.size();
int[] visibleTaskRange = mTmpIntPair;
visibleTaskRange[0] = -1;
@@ -430,7 +436,7 @@
// Calculate the current and (if necessary) the target transform for the task
transform = mLayoutAlgorithm.getStackTransform(task, curStackScroll,
- taskTransforms.get(i), frontTransform);
+ taskTransforms.get(i), frontTransform, ignoreTaskOverrides);
if (useTargetStackScroll && !transform.visible) {
// If we have a target stack scroll and the task is not currently visible, then we
// just update the transform at the new scroll
@@ -468,11 +474,13 @@
/**
* Binds the visible {@link TaskView}s at the given target scroll.
- *
- * @see #bindVisibleTaskViews(float, ArraySet<Task.TaskKey>)
*/
void bindVisibleTaskViews(float targetStackScroll) {
- bindVisibleTaskViews(targetStackScroll, mIgnoreTasks);
+ bindVisibleTaskViews(targetStackScroll, mIgnoreTasks, false /* ignoreTaskOverrides */);
+ }
+
+ void bindVisibleTaskViews(float targetStackScroll, boolean ignoreTaskOverrides) {
+ bindVisibleTaskViews(targetStackScroll, mIgnoreTasks, ignoreTaskOverrides);
}
/**
@@ -487,12 +495,16 @@
* target stack scroll.
* @param ignoreTasksSet The set of tasks to ignore in this rebinding of the visible
* {@link TaskView}s
+ * @param ignoreTaskOverrides If set, the visible task computation will get the transforms for
+ * tasks at their non-overridden task progress
*/
- void bindVisibleTaskViews(float targetStackScroll, ArraySet<Task.TaskKey> ignoreTasksSet) {
+ void bindVisibleTaskViews(float targetStackScroll, ArraySet<Task.TaskKey> ignoreTasksSet,
+ boolean ignoreTaskOverrides) {
// Get all the task transforms
ArrayList<Task> tasks = mStack.getStackTasks();
int[] visibleTaskRange = computeVisibleTaskTransforms(mCurrentTaskTransforms, tasks,
- mStackScroller.getStackScroll(), targetStackScroll, ignoreTasksSet);
+ mStackScroller.getStackScroll(), targetStackScroll, ignoreTasksSet,
+ ignoreTaskOverrides);
// Return all the invisible children to the pool
mTmpTaskViewMap.clear();
@@ -605,7 +617,8 @@
cancelAllTaskViewAnimations();
// Synchronize the current set of TaskViews
- bindVisibleTaskViews(mStackScroller.getStackScroll(), ignoreTasksSet);
+ bindVisibleTaskViews(mStackScroller.getStackScroll(), ignoreTasksSet,
+ false /* ignoreTaskOverrides */);
// Animate them to their final transforms with the given animation
List<TaskView> taskViews = getTaskViews();
@@ -657,7 +670,8 @@
transform.fillIn(tv);
} else {
mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(),
- focusState, transform, null, true /* forceUpdate */);
+ focusState, transform, null, true /* forceUpdate */,
+ false /* ignoreTaskOverrides */);
}
transform.visible = true;
}
@@ -674,7 +688,7 @@
Task task = tasks.get(i);
TaskViewTransform transform = transformsOut.get(i);
mLayoutAlgorithm.getStackTransform(task, stackScroll, focusState, transform, null,
- true /* forceUpdate */);
+ true /* forceUpdate */, true /* ignoreTaskOverrides */);
transform.visible = true;
}
}
@@ -759,9 +773,7 @@
}
}
tv.getViewBounds().setClipBottom(clipBottom);
- if (!config.useHardwareLayers) {
- tv.mThumbnailView.updateThumbnailVisibility(clipBottom - tv.getPaddingBottom());
- }
+ tv.mThumbnailView.updateThumbnailVisibility(clipBottom - tv.getPaddingBottom());
prevVisibleTv = tv;
}
mTaskViewsClipDirty = false;
@@ -860,6 +872,7 @@
cancelAllTaskViewAnimations();
}
+ mLayoutAlgorithm.clearUnfocusedTaskOverrides();
willScroll = mAnimationHelper.startScrollToFocusedTaskAnimation(newFocusedTask,
requestViewFocus);
} else {
@@ -1162,11 +1175,16 @@
// If this is the first layout, then scroll to the front of the stack, then update the
// TaskViews with the stack so that we can lay them out
- if (mAwaitingFirstLayout) {
- mStackScroller.setStackScrollToInitialState();
+ // TODO: The second check is a workaround for wacky layouts that we get while docking via
+ // long pressing the recents button
+ if (mAwaitingFirstLayout ||
+ (mStackScroller.getStackScroll() == mLayoutAlgorithm.mInitialScrollP)) {
+ updateToInitialState();
}
+
// Rebind all the views, including the ignore ones
- bindVisibleTaskViews(mStackScroller.getStackScroll(), EMPTY_TASK_SET);
+ bindVisibleTaskViews(mStackScroller.getStackScroll(), EMPTY_TASK_SET,
+ false /* ignoreTaskOverrides */);
// Measure each of the TaskViews
mTmpTaskViews.clear();
@@ -1458,7 +1476,7 @@
Recents.getTaskLoader().loadTaskData(task, true /* fetchAndInvalidateThumbnails */);
// If the doze trigger has already fired, then update the state for this task view
- if (mUIDozeTrigger.hasTriggered()) {
+ if (mUIDozeTrigger.isAsleep()) {
tv.setNoUserInteractionState();
}
@@ -1859,6 +1877,12 @@
});
}
+ public final void onBusEvent(ConfigurationChangedEvent event) {
+ mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
+ mLayoutAlgorithm.initialize(mStackBounds,
+ TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
+ }
+
/**
* Removes the task from the stack, and updates the focus to the next task in the stack if the
* removed TaskView was focused.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index 333df9d..ad46abd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -115,13 +115,8 @@
* @return whether the stack progress changed.
*/
public boolean setStackScrollToInitialState() {
- SystemServicesProxy ssp = Recents.getSystemServices();
float prevStackScrollP = mStackScrollP;
- if (ssp.hasDockedTask()) {
- setStackScroll(mLayoutAlgorithm.mMaxScrollP);
- } else {
- setStackScroll(mLayoutAlgorithm.mInitialScrollP);
- }
+ setStackScroll(mLayoutAlgorithm.mInitialScrollP);
return Float.compare(prevStackScrollP, mStackScrollP) != 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 20933ee..52f8fc8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -446,7 +446,7 @@
}
// Pick up the newly visible views, not including the deleting tasks
- mSv.bindVisibleTaskViews(newStackScroll);
+ mSv.bindVisibleTaskViews(newStackScroll, true /* ignoreTaskOverrides */);
// Get the final set of task transforms (with task removed)
mSv.getLayoutTaskTransforms(newStackScroll, TaskStackLayoutAlgorithm.STATE_UNFOCUSED,
@@ -486,6 +486,7 @@
mSv.getScroller().setStackScroll(mTargetStackScroll, null);
// Update the focus state to the final focus state
mSv.getStackAlgorithm().setFocusState(TaskStackLayoutAlgorithm.STATE_UNFOCUSED);
+ mSv.getStackAlgorithm().clearUnfocusedTaskOverrides();
// Remove the task view from the stack
EventBus.getDefault().send(new TaskViewDismissedEvent(tv.getTask(), tv));
// Stop tracking this deletion animation
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 2e7c7f2..e9c7ac6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -77,6 +77,24 @@
/**
* The dim overlay is generally calculated from the task progress, but occasionally (like when
+ * launching) needs to be animated independently of the task progress. This call is only used
+ * when animating the task into Recents, when the header dim is already applied
+ */
+ public static final Property<TaskView, Float> DIM_ALPHA_WITHOUT_HEADER =
+ new FloatProperty<TaskView>("dimAlphaWithoutHeader") {
+ @Override
+ public void setValue(TaskView tv, float dimAlpha) {
+ tv.setDimAlphaWithoutHeader(dimAlpha);
+ }
+
+ @Override
+ public Float get(TaskView tv) {
+ return tv.getDimAlpha();
+ }
+ };
+
+ /**
+ * The dim overlay is generally calculated from the task progress, but occasionally (like when
* launching) needs to be animated independently of the task progress.
*/
public static final Property<TaskView, Float> DIM_ALPHA =
@@ -388,21 +406,17 @@
* Sets the current dim.
*/
public void setDimAlpha(float dimAlpha) {
- RecentsConfiguration config = Recents.getConfiguration();
-
- int dimAlphaInt = (int) (dimAlpha * 255);
mDimAlpha = dimAlpha;
- if (config.useHardwareLayers) {
- // Defer setting hardware layers if we have not yet measured, or there is no dim to draw
- if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) {
- mDimColorFilter.setColor(Color.argb(dimAlphaInt, 0, 0, 0));
- mDimLayerPaint.setColorFilter(mDimColorFilter);
- mContent.setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint);
- }
- } else {
- mThumbnailView.setDimAlpha(dimAlpha);
- mHeaderView.setDimAlpha(dimAlpha);
- }
+ mThumbnailView.setDimAlpha(dimAlpha);
+ mHeaderView.setDimAlpha(dimAlpha);
+ }
+
+ /**
+ * Sets the current dim without updating the header's dim.
+ */
+ public void setDimAlphaWithoutHeader(float dimAlpha) {
+ mDimAlpha = dimAlpha;
+ mThumbnailView.setDimAlpha(dimAlpha);
}
/**
@@ -413,25 +427,6 @@
}
/**
- * Animates the dim to the given value.
- */
- void animateDimAlpha(float toDimAlpha, AnimationProps animation) {
- // Animate the dim into view as well
- if (Float.compare(toDimAlpha, getDimAlpha()) != 0) {
- Animator anim = animation.apply(AnimationProps.DIM_ALPHA, ObjectAnimator.ofFloat(this,
- DIM_ALPHA, getDimAlpha(), toDimAlpha));
- if (animation.getListener() != null) {
- anim.addListener(animation.getListener());
- }
- anim.start();
- } else {
- if (animation.getListener() != null) {
- animation.getListener().onAnimationEnd(null);
- }
- }
- }
-
- /**
* Explicitly sets the focused state of this task.
*/
public void setFocusedState(boolean isFocused, boolean requestViewFocus) {
@@ -517,18 +512,20 @@
@Override
public void onPrepareLaunchTargetForEnterAnimation() {
// These values will be animated in when onStartLaunchTargetEnterAnimation() is called
- setDimAlpha(0);
+ setDimAlphaWithoutHeader(0);
mActionButtonView.setAlpha(0f);
}
@Override
- public void onStartLaunchTargetEnterAnimation(int duration, boolean screenPinningEnabled,
- ReferenceCountedTrigger postAnimationTrigger) {
- // Un-dim the view before/while launching the target
- AnimationProps animation = new AnimationProps(duration, Interpolators.ALPHA_OUT)
- .setListener(postAnimationTrigger.decrementOnAnimationEnd());
+ public void onStartLaunchTargetEnterAnimation(TaskViewTransform transform, int duration,
+ boolean screenPinningEnabled, ReferenceCountedTrigger postAnimationTrigger) {
+ // Dim the view after the app window transitions down into recents
postAnimationTrigger.increment();
- animateDimAlpha(0, animation);
+ AnimationProps animation = new AnimationProps(duration, Interpolators.ALPHA_OUT);
+ Animator anim = animation.apply(AnimationProps.DIM_ALPHA, ObjectAnimator.ofFloat(this,
+ DIM_ALPHA_WITHOUT_HEADER, getDimAlpha(), transform.dimAlpha));
+ anim.addListener(postAnimationTrigger.decrementOnAnimationEnd());
+ anim.start();
if (screenPinningEnabled) {
showActionButton(true /* fadeIn */, duration /* fadeInDuration */);
@@ -540,7 +537,9 @@
ReferenceCountedTrigger postAnimationTrigger) {
// Un-dim the view before/while launching the target
AnimationProps animation = new AnimationProps(duration, Interpolators.ALPHA_OUT);
- animateDimAlpha(0, animation);
+ Animator anim = animation.apply(AnimationProps.DIM_ALPHA, ObjectAnimator.ofFloat(this,
+ DIM_ALPHA, getDimAlpha(), 0));
+ anim.start();
postAnimationTrigger.increment();
hideActionButton(true /* fadeOut */, duration,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 05a8527..b2a7d90 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -347,9 +347,11 @@
* Sets the dim alpha, only used when we are not using hardware layers.
* (see RecentsConfiguration.useHardwareLayers)
*/
- void setDimAlpha(float dimAlpha) {
- mDimAlpha = dimAlpha;
- updateBackgroundColor(mBackground.getColor(), dimAlpha);
+ public void setDimAlpha(float dimAlpha) {
+ if (Float.compare(mDimAlpha, dimAlpha) != 0) {
+ mDimAlpha = dimAlpha;
+ updateBackgroundColor(mBackground.getColor(), dimAlpha);
+ }
}
/**
@@ -377,7 +379,9 @@
int primaryColor = disabledInSafeMode
? mDisabledTaskBarBackgroundColor
: t.colorPrimary;
- updateBackgroundColor(primaryColor, mDimAlpha);
+ if (mBackground.getColor() != primaryColor) {
+ updateBackgroundColor(primaryColor, mDimAlpha);
+ }
if (t.icon != null) {
mIconView.setImageDrawable(t.icon);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 178838e..143f160 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -194,6 +194,7 @@
// public mode, private notifications, etc
private boolean mLockscreenPublicMode = false;
private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
+ private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
private UserManager mUserManager;
private int mDensity;
@@ -1089,6 +1090,8 @@
@Override
public void onGearDisplayed(ExpandableNotificationRow row) {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_REVEAL_GEAR,
+ row.getStatusBarNotification().getPackageName());
mNotificationGearDisplayed = row;
}
@@ -1302,6 +1305,26 @@
}
/**
+ * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
+ * "public" (secure & locked) mode?
+ */
+ public boolean userAllowsNotificationsInPublic(int userHandle) {
+ if (userHandle == UserHandle.USER_ALL) {
+ return true;
+ }
+
+ if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
+ final boolean allowed = 0 != Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
+ mUsersAllowingNotifications.append(userHandle, allowed);
+ return allowed;
+ }
+
+ return mUsersAllowingNotifications.get(userHandle);
+ }
+
+ /**
* Has the given user chosen to allow their private (full) notifications to be shown even
* when the lockscreen is in "public" (secure & locked) mode?
*/
@@ -1333,13 +1356,30 @@
}
/**
- * Returns true if we're on a secure lockscreen and the user wants to hide "sensitive"
- * notification data. If so, private notifications should show their (possibly
- * auto-generated) publicVersion, and secret notifications should be totally invisible.
+ * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
+ * If so, notifications should be hidden.
*/
@Override // NotificationData.Environment
- public boolean shouldHideSensitiveContents(int userid) {
- return isLockscreenPublicMode() && !userAllowsPrivateNotificationsInPublic(userid);
+ public boolean shouldHideNotifications(int userid) {
+ return isLockscreenPublicMode() && !userAllowsNotificationsInPublic(userid);
+ }
+
+ /**
+ * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
+ * package-specific override.
+ */
+ @Override // NotificationDate.Environment
+ public boolean shouldHideNotifications(String key) {
+ return isLockscreenPublicMode()
+ && mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_SECRET;
+ }
+
+ /**
+ * Returns true if we're on a secure lockscreen.
+ */
+ @Override // NotificationData.Environment
+ public boolean onSecureLockScreen() {
+ return isLockscreenPublicMode();
}
public void onNotificationClear(StatusBarNotification notification) {
@@ -1851,7 +1891,7 @@
}
}
- protected abstract boolean isPanelFullyCollapsed();
+ public abstract boolean isPanelFullyCollapsed();
/**
* Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index f446593..12a83fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -105,7 +105,6 @@
private boolean mClearable;
private ExpansionLogger mLogger;
private String mLoggingKey;
- private boolean mWasReset;
private NotificationSettingsIconRow mSettingsIconRow;
private NotificationGuts mGuts;
private NotificationData.Entry mEntry;
@@ -615,20 +614,16 @@
mShowingPublicInitialized = false;
mIsSystemExpanded = false;
mOnKeyguard = false;
- mPublicLayout.reset(mIsHeadsUp);
- mPrivateLayout.reset(mIsHeadsUp);
+ mPublicLayout.reset();
+ mPrivateLayout.reset();
resetHeight();
resetTranslation();
logExpansionEvent(false, wasExpanded);
}
public void resetHeight() {
- if (mIsHeadsUp) {
- resetActualHeight();
- }
mMaxExpandHeight = 0;
mHeadsUpHeight = 0;
- mWasReset = true;
onHeightReset();
requestLayout();
}
@@ -684,7 +679,7 @@
mTranslateableViews.remove(mGutsStub);
}
- public void setTranslationForOutline(float translationX) {
+ private void setTranslationForOutline(float translationX) {
setOutlineRect(false, translationX, getTop(), getRight() + translationX, getBottom());
}
@@ -704,6 +699,46 @@
if (mTranslateAnim != null) {
mTranslateAnim.cancel();
}
+ mTranslateAnim = (AnimatorSet) getTranslateViewAnimator(leftTarget,
+ null /* updateListener */);
+ if (mTranslateAnim != null) {
+ mTranslateAnim.start();
+ }
+ }
+
+ @Override
+ public void setTranslation(float translationX) {
+ if (areGutsExposed()) {
+ // Don't translate if guts are showing.
+ return;
+ }
+ // Translate the group of views
+ for (int i = 0; i < mTranslateableViews.size(); i++) {
+ if (mTranslateableViews.get(i) != null) {
+ mTranslateableViews.get(i).setTranslationX(translationX);
+ }
+ }
+ setTranslationForOutline(translationX);
+ if (mSettingsIconRow != null) {
+ mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
+ }
+ }
+
+ @Override
+ public float getTranslation() {
+ if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
+ // All of the views in the list should have same translation, just use first one.
+ return mTranslateableViews.get(0).getTranslationX();
+ }
+ return 0;
+ }
+
+ public Animator getTranslateViewAnimator(final float leftTarget,
+ AnimatorUpdateListener listener) {
+ if (areGutsExposed()) {
+ // No translation if guts are exposed.
+ return null;
+ }
AnimatorSet set = new AnimatorSet();
if (mTranslateableViews != null) {
for (int i = 0; i < mTranslateableViews.size(); i++) {
@@ -715,8 +750,15 @@
@Override
public void onAnimationUpdate(ValueAnimator animation) {
setTranslationForOutline((float) animation.getAnimatedValue());
+ if (mSettingsIconRow != null) {
+ mSettingsIconRow.updateSettingsIcons(
+ (float) animation.getAnimatedValue(), getMeasuredWidth());
+ }
}
});
+ if (listener != null) {
+ translateAnim.addUpdateListener(listener);
+ }
}
translateAnim.addListener(new AnimatorListenerAdapter() {
@Override
@@ -730,8 +772,7 @@
set.play(translateAnim);
}
}
- mTranslateAnim = set;
- set.start();
+ return set;
}
public float getSpaceForGear() {
@@ -748,10 +789,6 @@
return mSettingsIconRow;
}
- public ArrayList<View> getContentViews() {
- return mTranslateableViews;
- }
-
public void inflateGuts() {
if (mGuts == null) {
mGutsStub.inflate();
@@ -922,18 +959,6 @@
return mStatusBarNotification != null && mStatusBarNotification.isClearable();
}
- /**
- * Apply an expansion state to the layout.
- */
- public void applyExpansionToLayout() {
- boolean expand = isExpanded();
- if (expand && mExpandable) {
- setActualHeight(mMaxExpandHeight);
- } else {
- setActualHeight(getMinHeight());
- }
- }
-
@Override
public int getIntrinsicHeight() {
if (isUserLocked()) {
@@ -1015,12 +1040,7 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- boolean updateExpandHeight = mMaxExpandHeight == 0 && !mWasReset;
updateMaxHeights();
- if (updateExpandHeight) {
- applyExpansionToLayout();
- }
- mWasReset = false;
}
private void updateMaxHeights() {
@@ -1169,6 +1189,10 @@
return mMaxExpandHeight;
}
+ public boolean areGutsExposed() {
+ return (mGuts != null && mGuts.areGutsExposed());
+ }
+
@Override
public boolean isContentExpandable() {
NotificationContentView showingLayout = getShowingLayout();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 1ff87f5..c0e4340 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -36,7 +36,6 @@
protected OnHeightChangedListener mOnHeightChangedListener;
private int mActualHeight;
protected int mClipTopAmount;
- private boolean mActualHeightInitialized;
private boolean mDark;
private ArrayList<View> mMatchParentViews = new ArrayList<View>();
private int mClipTopOptimization;
@@ -99,28 +98,9 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- if (!mActualHeightInitialized && mActualHeight == 0) {
- int initialHeight = getInitialHeight();
- if (initialHeight != 0) {
- setActualHeight(initialHeight);
- }
- }
updateClipping();
}
- /**
- * Resets the height of the view on the next layout pass
- */
- protected void resetActualHeight() {
- mActualHeight = 0;
- mActualHeightInitialized = false;
- requestLayout();
- }
-
- protected int getInitialHeight() {
- return getHeight();
- }
-
@Override
public boolean pointInView(float localX, float localY, float slop) {
float top = mClipTopAmount;
@@ -137,7 +117,6 @@
* @param notifyListeners Whether the listener should be informed about the change.
*/
public void setActualHeight(int actualHeight, boolean notifyListeners) {
- mActualHeightInitialized = true;
mActualHeight = actualHeight;
updateClipping();
if (notifyListeners) {
@@ -283,6 +262,20 @@
public void setBelowSpeedBump(boolean below) {
}
+ /**
+ * Sets the translation of the view.
+ */
+ public void setTranslation(float translation) {
+ setTranslationX(translation);
+ }
+
+ /**
+ * Gets the translation of the view.
+ */
+ public float getTranslation() {
+ return getTranslationX();
+ }
+
public void onHeightReset() {
if (mOnHeightChangedListener != null) {
mOnHeightChangedListener.onReset(this);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 7c11161..b94c15b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -92,7 +92,14 @@
= new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
- mAnimate = true;
+ // We need to post since we don't want the notification to animate on the very first
+ // frame
+ post(new Runnable() {
+ @Override
+ public void run() {
+ mAnimate = true;
+ }
+ });
getViewTreeObserver().removeOnPreDrawListener(this);
return true;
}
@@ -113,7 +120,7 @@
R.dimen.min_notification_layout_height);
mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_content_margin_end);
- reset(true);
+ reset();
}
public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight) {
@@ -248,7 +255,7 @@
updateVisibility();
}
- public void reset(boolean resetActualHeight) {
+ public void reset() {
if (mContractedChild != null) {
mContractedChild.animate().cancel();
removeView(mContractedChild);
@@ -264,10 +271,6 @@
mContractedChild = null;
mExpandedChild = null;
mHeadsUpChild = null;
- mVisibleType = VISIBLE_TYPE_CONTRACTED;
- if (resetActualHeight) {
- mContentHeight = mSmallHeight;
- }
}
public View getContractedChild() {
@@ -477,12 +480,18 @@
private void animateToVisibleType(int visibleType) {
final TransformableView shownView = getTransformableViewForVisibleType(visibleType);
final TransformableView hiddenView = getTransformableViewForVisibleType(mVisibleType);
+ if (shownView == hiddenView) {
+ shownView.setVisible(true);
+ return;
+ }
shownView.transformFrom(hiddenView);
getViewForVisibleType(visibleType).setVisibility(View.VISIBLE);
hiddenView.transformTo(shownView, new Runnable() {
@Override
public void run() {
- hiddenView.setVisible(false);
+ if (hiddenView != getTransformableViewForVisibleType(mVisibleType)) {
+ hiddenView.setVisible(false);
+ }
}
});
}
@@ -543,6 +552,9 @@
|| mContainingNotification.isExpanded()
? mContainingNotification.getMaxContentHeight()
: mContainingNotification.getShowingLayout().getMinHeight();
+ if (height == 0) {
+ height = mContentHeight;
+ }
int expandedVisualType = getVisualTypeForHeight(height);
int collapsedVisualType = getVisualTypeForHeight(
mContainingNotification.getMinExpandHeight());
@@ -550,7 +562,12 @@
? expandedVisualType
: collapsedVisualType;
}
- int viewHeight = Math.min(mContentHeight, mContainingNotification.getIntrinsicHeight());
+ int intrinsicHeight = mContainingNotification.getIntrinsicHeight();
+ int viewHeight = mContentHeight;
+ if (intrinsicHeight != 0) {
+ // the intrinsicHeight might be 0 because it was just reset.
+ viewHeight = Math.min(mContentHeight, intrinsicHeight);
+ }
return getVisualTypeForHeight(viewHeight);
}
@@ -631,7 +648,6 @@
mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
updateSingleLineView();
applyRemoteInput(entry);
- selectLayout(false /* animate */, true /* force */);
if (mContractedChild != null) {
mContractedWrapper.notifyContentUpdated(entry.notification);
}
@@ -641,6 +657,7 @@
if (mHeadsUpChild != null) {
mHeadsUpWrapper.notifyContentUpdated(entry.notification);
}
+ selectLayout(false /* animate */, true /* force */);
setDark(mDark, false /* animate */, 0 /* delay */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 7cb9127..c9fe2bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -353,8 +353,10 @@
return true;
}
- if (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET &&
- mEnvironment.shouldHideSensitiveContents(sbn.getUserId())) {
+ if (mEnvironment.onSecureLockScreen() &&
+ (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET
+ || mEnvironment.shouldHideNotifications(sbn.getUserId())
+ || mEnvironment.shouldHideNotifications(sbn.getKey()))) {
return true;
}
@@ -433,7 +435,9 @@
* Provides access to keyguard state and user settings dependent data.
*/
public interface Environment {
- public boolean shouldHideSensitiveContents(int userid);
+ public boolean onSecureLockScreen();
+ public boolean shouldHideNotifications(int userid);
+ public boolean shouldHideNotifications(String key);
public boolean isDeviceProvisioned();
public boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
public String getCurrentMediaNotificationKey();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 1c16bdc..45a24a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -130,7 +130,12 @@
importanceSlider.setVisibility(View.VISIBLE);
importanceButtons.setVisibility(View.GONE);
} else {
- bindToggles(importanceButtons, sbn, systemApp);
+ int userImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
+ try {
+ userImportance =
+ mINotificationManager.getImportance(sbn.getPackageName(), sbn.getUid());
+ } catch (RemoteException e) {}
+ bindToggles(importanceButtons, userImportance, systemApp);
importanceButtons.setVisibility(View.VISIBLE);
importanceSlider.setVisibility(View.GONE);
}
@@ -144,7 +149,7 @@
if (mBlock.isChecked()) {
progress = NotificationListenerService.Ranking.IMPORTANCE_NONE;
} else if (mSilent.isChecked()) {
- progress = NotificationListenerService.Ranking.IMPORTANCE_DEFAULT;
+ progress = NotificationListenerService.Ranking.IMPORTANCE_LOW;
} else {
progress = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
}
@@ -158,7 +163,7 @@
}
}
- private void bindToggles(final View importanceButtons, final StatusBarNotification sbn,
+ private void bindToggles(final View importanceButtons, final int importance,
final boolean systemApp) {
mBlock = (RadioButton) importanceButtons.findViewById(R.id.block_importance);
mSilent = (RadioButton) importanceButtons.findViewById(R.id.silent_importance);
@@ -169,7 +174,11 @@
} else {
mReset.setText(mContext.getString(R.string.do_not_silence_block));
}
- mReset.setChecked(true);
+ if (importance == NotificationListenerService.Ranking.IMPORTANCE_LOW) {
+ mSilent.setChecked(true);
+ } else {
+ mReset.setChecked(true);
+ }
}
private void bindSlider(final View importanceSlider, final StatusBarNotification sbn,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 960e4cf..988d537 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -221,6 +221,7 @@
apply();
applyIconTint();
+ mNC.addSignalCallback(this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
index bf05d1d..66f945e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
@@ -76,26 +76,26 @@
});
mViewTransformationAnimation.setInterpolator(Interpolators.LINEAR);
mViewTransformationAnimation.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- if (endRunnable != null) {
- mViewTransformationAnimation.addListener(new AnimatorListenerAdapter() {
- public boolean mCancelled;
+ mViewTransformationAnimation.addListener(new AnimatorListenerAdapter() {
+ public boolean mCancelled;
- @Override
- public void onAnimationEnd(Animator animation) {
- endRunnable.run();
- if (!mCancelled) {
- setVisible(false);
- } else {
- abortTransformations();
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mCancelled) {
+ if (endRunnable != null) {
+ endRunnable.run();
}
+ setVisible(false);
+ } else {
+ abortTransformations();
}
+ }
- @Override
- public void onAnimationCancel(Animator animation) {
- mCancelled = true;
- }
- });
- }
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+ });
mViewTransformationAnimation.start();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 127feba..88b8afa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1397,7 +1397,7 @@
// In Shade, interpolate linearly such that QS is closed whenever panel height is
// minimum QS expansion + minStackHeight
float panelHeightQsCollapsed = mNotificationStackScroller.getIntrinsicPadding()
- + mNotificationStackScroller.getMinStackHeight();
+ + mNotificationStackScroller.getLayoutMinHeight();
float panelHeightQsExpanded = calculatePanelHeightQsExpanded();
t = (expandedHeight - panelHeightQsCollapsed)
/ (panelHeightQsExpanded - panelHeightQsCollapsed);
@@ -1453,7 +1453,7 @@
&& mShadeEmpty) {
notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight()
+ mNotificationStackScroller.getBottomStackPeekSize()
- + mNotificationStackScroller.getCollapseSecondCardPadding();
+ + mNotificationStackScroller.getBottomStackSlowDownHeight();
}
int maxQsHeight = mQsMaxExpansionHeight;
@@ -1468,7 +1468,7 @@
+ notificationHeight;
if (totalHeight > mNotificationStackScroller.getHeight()) {
float fullyCollapsedHeight = maxQsHeight
- + mNotificationStackScroller.getMinStackHeight();
+ + mNotificationStackScroller.getLayoutMinHeight();
totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight());
}
return (int) totalHeight;
@@ -1485,7 +1485,7 @@
private float getFadeoutAlpha() {
float alpha = (getNotificationsTopY() + mNotificationStackScroller.getFirstItemMinHeight())
/ (mQsMinExpansionHeight + mNotificationStackScroller.getBottomStackPeekSize()
- - mNotificationStackScroller.getCollapseSecondCardPadding());
+ - mNotificationStackScroller.getBottomStackSlowDownHeight());
alpha = Math.max(0, Math.min(alpha, 1));
alpha = (float) Math.pow(alpha, 0.75);
return alpha;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index e739944..073a848 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -995,7 +995,6 @@
SignalClusterView signalCluster =
(SignalClusterView) containerView.findViewById(R.id.signal_cluster);
if (signalCluster != null) {
- mNetworkController.addSignalCallback(signalCluster);
signalCluster.setSecurityController(mSecurityController);
signalCluster.setNetworkController(mNetworkController);
}
@@ -1597,8 +1596,7 @@
}
private boolean packageHasVisibilityOverride(String key) {
- return mNotificationData.getVisibilityOverride(key)
- != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
+ return mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_PRIVATE;
}
private void updateClearAll() {
@@ -3556,7 +3554,7 @@
}
@Override
- protected boolean isPanelFullyCollapsed() {
+ public boolean isPanelFullyCollapsed() {
return mNotificationPanel.isFullyCollapsed();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 256cc6b..326ca2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -296,7 +296,6 @@
mHost = host;
host.setHeaderView(this);
mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
- mHeaderQsPanel.setMaxTiles(5);
mHeaderQsPanel.setHost(host);
setUserInfoController(host.getUserInfoController());
setBatteryController(host.getBatteryController());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java
index bd36462..159bd41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java
@@ -19,6 +19,7 @@
import android.net.NetworkCapabilities;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import java.util.BitSet;
@@ -46,12 +47,12 @@
}
@Override
- public void notifyListeners() {
+ public void notifyListeners(SignalCallback callback) {
boolean ethernetVisible = mCurrentState.connected;
String contentDescription = getStringIfExists(getContentDescription());
// TODO: wire up data transfer using WifiSignalPoller.
- mCallbackHandler.setEthernetIndicators(new IconState(ethernetVisible, getCurrentIconId(),
+ callback.setEthernetIndicators(new IconState(ethernetVisible, getCurrentIconId(),
contentDescription));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 8fd4d9c..80dcfb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -34,6 +34,7 @@
import com.android.internal.telephony.cdma.EriInfo;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
@@ -198,7 +199,7 @@
}
@Override
- public void notifyListeners() {
+ public void notifyListeners(SignalCallback callback) {
MobileIconGroup icons = getIcons();
String contentDescription = getStringIfExists(getContentDescription());
@@ -231,7 +232,7 @@
|| mCurrentState.iconGroup == TelephonyIcons.ROAMING
|| mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED;
int typeIcon = showDataIcon ? icons.mDataType : 0;
- mCallbackHandler.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
+ callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
activityIn, activityOut, dataContentDescription, description, icons.mIsWide,
mSubscriptionInfo.getSubscriptionId());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 8193b52..40eb71d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -322,16 +322,16 @@
}
public void addSignalCallback(SignalCallback cb) {
- mCallbackHandler.setListening(cb, true);
- mCallbackHandler.setSubs(mCurrentSubscriptions);
- mCallbackHandler.setIsAirplaneMode(new IconState(mAirplaneMode,
+ cb.setSubs(mCurrentSubscriptions);
+ cb.setIsAirplaneMode(new IconState(mAirplaneMode,
TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
- mCallbackHandler.setNoSims(mHasNoSims);
- mWifiSignalController.notifyListeners();
- mEthernetSignalController.notifyListeners();
+ cb.setNoSims(mHasNoSims);
+ mWifiSignalController.notifyListeners(cb);
+ mEthernetSignalController.notifyListeners(cb);
for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
- mobileSignalController.notifyListeners();
+ mobileSignalController.notifyListeners(cb);
}
+ mCallbackHandler.setListening(cb, true);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
index c954d08..4cfd1c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.text.format.DateFormat;
import android.util.Log;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import java.io.PrintWriter;
import java.util.BitSet;
@@ -48,7 +49,7 @@
// is aware of current state.
protected final NetworkControllerImpl mNetworkController;
- protected final CallbackHandler mCallbackHandler;
+ private final CallbackHandler mCallbackHandler;
// Save the previous HISTORY_SIZE states for logging.
private final State[] mHistory;
@@ -198,12 +199,16 @@
}
}
+ public final void notifyListeners() {
+ notifyListeners(mCallbackHandler);
+ }
+
/**
* Trigger callbacks based on current state. The callbacks should be completely
* based on current state, and only need to be called in the scenario where
* mCurrentState != mLastState.
*/
- public abstract void notifyListeners();
+ public abstract void notifyListeners(SignalCallback callback);
/**
* Generate a blank T.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index cc98eb6..a6ed04f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -28,6 +28,7 @@
import com.android.internal.util.AsyncChannel;
import com.android.settingslib.wifi.WifiStatusTracker;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import java.util.Objects;
@@ -72,7 +73,7 @@
}
@Override
- public void notifyListeners() {
+ public void notifyListeners(SignalCallback callback) {
// only show wifi in the cluster if connected or if wifi-only
boolean wifiVisible = mCurrentState.enabled
&& (mCurrentState.connected || !mHasMobileData);
@@ -83,7 +84,7 @@
IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription);
IconState qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconId(),
contentDescription);
- mCallbackHandler.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
+ callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut,
wifiDesc);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 85b1426..aa444f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -48,6 +48,8 @@
import android.view.animation.Interpolator;
import android.widget.OverScroller;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.ExpandHelper;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -363,6 +365,8 @@
@Override
public void onGearTouched(ExpandableNotificationRow row, int x, int y) {
if (mLongPressListener != null) {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_TOUCH_GEAR,
+ row.getStatusBarNotification().getPackageName());
mLongPressListener.onLongPress(row, x, y);
}
}
@@ -418,12 +422,9 @@
.getDimensionPixelSize(R.dimen.notification_divider_height));
mIncreasedPaddingBetweenElements = context.getResources()
.getDimensionPixelSize(R.dimen.notification_divider_height_increased);
-
mBottomStackSlowDownHeight = mStackScrollAlgorithm.getBottomStackSlowDownLength();
mMinTopOverScrollToEscape = getResources().getDimensionPixelSize(
R.dimen.min_top_overscroll_to_qs);
- mCollapseSecondCardPadding = getResources().getDimensionPixelSize(
- R.dimen.notification_collapse_second_card_padding);
}
private void notifyHeightChangeListener(ExpandableView view) {
@@ -509,14 +510,6 @@
}
/**
- * @return whether the height of the layout needs to be adapted, in order to ensure that the
- * last child is not in the bottom stack.
- */
- private boolean needsHeightAdaption() {
- return getNotGoneChildCount() > 1;
- }
-
- /**
* Updates the children views according to the stack scroll algorithm. Call this whenever
* modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout.
*/
@@ -599,7 +592,7 @@
mLastSetStackHeight = height;
setIsExpanded(height > 0.0f);
int newStackHeight = (int) height;
- int minStackHeight = getMinStackHeight();
+ int minStackHeight = getLayoutMinHeight();
int stackHeight;
float paddingOffset;
boolean trackingHeadsUp = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp();
@@ -612,20 +605,7 @@
stackHeight = newStackHeight;
} else {
int translationY;
- if (!trackingHeadsUp) {
- // We did not reach the position yet where we actually start growing,
- // so we translate the stack upwards.
- translationY = (newStackHeight - minStackHeight);
- // A slight parallax effect is introduced in order for the stack to catch up with
- // the top card.
- float partiallyThere = (newStackHeight - mTopPadding - mTopPaddingOverflow)
- / minStackHeight;
- partiallyThere = Math.max(0, partiallyThere);
- translationY += (1 - partiallyThere) * (mBottomStackPeekSize +
- mCollapseSecondCardPadding);
- } else {
- translationY = (int) (height - normalUnfoldPositionStart);
- }
+ translationY = newStackHeight - normalUnfoldPositionStart;
paddingOffset = translationY - mTopPadding;
stackHeight = (int) (height - (translationY - mTopPadding));
}
@@ -668,8 +648,8 @@
return mBottomStackPeekSize;
}
- public int getCollapseSecondCardPadding() {
- return mCollapseSecondCardPadding;
+ public int getBottomStackSlowDownHeight() {
+ return mBottomStackSlowDownHeight;
}
public void setLongPressListener(SwipeHelper.LongPressListener listener) {
@@ -734,6 +714,7 @@
if (targetLeft == 0 && mCurrIconRow != null) {
mCurrIconRow.resetState();
+ mCurrIconRow = null;
if (mGearExposedView != null && mGearExposedView == mTranslatingParentView) {
mGearExposedView = null;
}
@@ -1850,7 +1831,7 @@
boolean ignoreIntrinsicPadding) {
float start = qsHeight;
float stackHeight = getHeight() - start;
- int minStackHeight = getMinStackHeight();
+ int minStackHeight = getLayoutMinHeight();
if (stackHeight <= minStackHeight) {
float overflow = minStackHeight - stackHeight;
stackHeight = minStackHeight;
@@ -1864,11 +1845,16 @@
setStackHeight(mLastSetStackHeight);
}
- public int getMinStackHeight() {
+ public int getLayoutMinHeight() {
final ExpandableView firstChild = getFirstChildNotGone();
- final int firstChildMinHeight = firstChild != null ? firstChild.getMinHeight()
+ int firstChildMinHeight = firstChild != null
+ ? firstChild.getIntrinsicHeight()
: mCollapsedSize;
- return firstChildMinHeight + mBottomStackPeekSize + mCollapseSecondCardPadding;
+ if (mOwnScrollY > 0) {
+ firstChildMinHeight = Math.max(firstChildMinHeight - mOwnScrollY, mCollapsedSize);
+ }
+ return Math.min(firstChildMinHeight + mBottomStackPeekSize + mBottomStackSlowDownHeight,
+ mMaxLayoutHeight - mTopPadding);
}
public float getTopPaddingOverflow() {
@@ -1880,7 +1866,7 @@
final int firstChildMinHeight = firstChild != null ? (int) firstChild.getMinHeight()
: mCollapsedSize;
return mIntrinsicPadding + firstChildMinHeight + mBottomStackPeekSize
- + mCollapseSecondCardPadding;
+ + mBottomStackSlowDownHeight;
}
private int clampPadding(int desiredPadding) {
@@ -1994,7 +1980,6 @@
}
private void onViewRemovedInternal(View child) {
- mStackScrollAlgorithm.notifyChildrenChanged(this);
if (mChangePositionInProgress) {
// This is only a position change, don't do anything special
return;
@@ -2175,7 +2160,6 @@
private void onViewAddedInternal(View child) {
updateHideSensitiveForChild(child);
- mStackScrollAlgorithm.notifyChildrenChanged(this);
((ExpandableView) child).setOnHeightChangedListener(this);
generateAddAnimation(child, false /* fromMoreCard */);
updateAnimationState(child);
@@ -2643,12 +2627,8 @@
}
public int getEmptyBottomMargin() {
- int emptyMargin = mMaxLayoutHeight - mContentHeight - mBottomStackPeekSize;
- if (needsHeightAdaption()) {
- emptyMargin -= mBottomStackSlowDownHeight;
- } else {
- emptyMargin -= mCollapseSecondCardPadding;
- }
+ int emptyMargin = mMaxLayoutHeight - mContentHeight - mBottomStackPeekSize
+ - mBottomStackSlowDownHeight;
return Math.max(emptyMargin, 0);
}
@@ -2659,12 +2639,10 @@
public void onExpansionStarted() {
mIsExpansionChanging = true;
- mStackScrollAlgorithm.onExpansionStarted(mCurrentStackScrollState);
}
public void onExpansionStopped() {
mIsExpansionChanging = false;
- mStackScrollAlgorithm.onExpansionStopped();
if (!mIsExpanded) {
mOwnScrollY = 0;
@@ -2732,7 +2710,6 @@
if (mIsExpanded && mAnimationsEnabled) {
mRequestViewResizeAnimationOnLayout = true;
}
- mStackScrollAlgorithm.onReset(view);
updateAnimationState(view);
updateChronometerForChild(view);
}
@@ -3163,15 +3140,7 @@
}
public int getDismissViewHeight() {
- int height = mDismissView.getHeight() + mPaddingBetweenElements;
-
- // Hack: Accommodate for additional distance when we only have one notification and the
- // dismiss all button.
- if (getNotGoneChildCount() == 2 && getLastChildNotGone() == mDismissView
- && getFirstChildNotGone() instanceof ActivatableNotificationView) {
- height += mCollapseSecondCardPadding;
- }
- return height;
+ return mDismissView.getHeight() + mPaddingBetweenElements;
}
public int getEmptyShadeViewHeight() {
@@ -3399,7 +3368,6 @@
private static final long GEAR_SHOW_DELAY = 60;
- private ArrayList<View> mTranslatingViews = new ArrayList<>();
private CheckForDrag mCheckForDrag;
private Handler mHandler;
private int mMoveState = MOVE_STATE_UNDEFINED;
@@ -3416,6 +3384,7 @@
// Reset check for drag gesture
mCheckForDrag = null;
+ mCurrIconRow = null;
// Slide back any notifications that might be showing a gear
resetExposedGearView();
@@ -3424,9 +3393,6 @@
// Set the listener for the current row's gear
mCurrIconRow = ((ExpandableNotificationRow) currView).getSettingsRow();
mCurrIconRow.setGearListener(NotificationStackScrollLayout.this);
-
- // And the translating children
- mTranslatingViews = ((ExpandableNotificationRow) currView).getContentViews();
}
mMoveState = MOVE_STATE_UNDEFINED;
}
@@ -3440,15 +3406,12 @@
}
mMoveState = newMoveState;
- if (view instanceof ExpandableNotificationRow) {
- ((ExpandableNotificationRow) view).setTranslationForOutline(translation);
- if (!isPinnedHeadsUp(view)) {
- // Only show the gear if we're not a heads up view.
- checkForDrag();
- if (mCurrIconRow != null) {
- mCurrIconRow.updateSettingsIcons(translation, getSize(view));
- }
- }
+ final boolean gutsExposed = (view instanceof ExpandableNotificationRow)
+ && ((ExpandableNotificationRow) view).areGutsExposed();
+
+ if (!isPinnedHeadsUp(view) && !gutsExposed) {
+ // Only show the gear if we're not a heads up view and guts aren't exposed.
+ checkForDrag();
}
}
@@ -3471,12 +3434,12 @@
(!fromLeft && absTrans >= snapBackThreshold * 0.4f
&& absTrans <= notiThreshold);
- if (pastGear && !isPinnedHeadsUp(animView)) {
+ if (pastGear && !isPinnedHeadsUp(animView)
+ && (animView instanceof ExpandableNotificationRow)) {
// bouncity
final float target = fromLeft ? snapBackThreshold : -snapBackThreshold;
mGearExposedView = mTranslatingParentView;
- if (mGearDisplayedListener != null
- && (animView instanceof ExpandableNotificationRow)) {
+ if (mGearDisplayedListener != null) {
mGearDisplayedListener.onGearDisplayed((ExpandableNotificationRow) animView);
}
super.snapChild(animView, target, velocity);
@@ -3486,38 +3449,16 @@
}
@Override
- public void onTranslationUpdate(View animView, float value, boolean canBeDismissed) {
- if (mDismissAllInProgress) {
- // When dismissing all, we translate the entire view instead.
- super.onTranslationUpdate(animView, value, canBeDismissed);
- return;
- }
- if (animView instanceof ExpandableNotificationRow) {
- ((ExpandableNotificationRow) animView).setTranslationForOutline(value);
- }
- if (mCurrIconRow != null) {
- mCurrIconRow.updateSettingsIcons(value, getSize(animView));
- }
- }
-
- @Override
public Animator getViewTranslationAnimator(View v, float target,
AnimatorUpdateListener listener) {
if (mDismissAllInProgress) {
// When dismissing all, we translate the entire view instead.
return super.getViewTranslationAnimator(v, target, listener);
+ } else if (v instanceof ExpandableNotificationRow) {
+ return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener);
+ } else {
+ return super.getViewTranslationAnimator(v, target, listener);
}
- ArrayList<Animator> animators = new ArrayList<Animator>();
- for (int i = 0; i < mTranslatingViews.size(); i++) {
- ObjectAnimator anim = createTranslationAnimation(mTranslatingViews.get(i), target);
- animators.add(anim);
- if (i == 0 && listener != null) {
- anim.addUpdateListener(listener);
- }
- }
- AnimatorSet set = new AnimatorSet();
- set.playTogether(animators);
- return set;
}
@Override
@@ -3525,13 +3466,8 @@
if (mDismissAllInProgress) {
// When dismissing all, we translate the entire view instead.
super.setTranslation(v, translate);
- return;
- }
- // Translate the group of views
- for (int i = 0; i < mTranslatingViews.size(); i++) {
- if (mTranslatingViews.get(i) != null) {
- super.setTranslation(mTranslatingViews.get(i), translate);
- }
+ } else {
+ ((ExpandableView) v).setTranslation(translate);
}
}
@@ -3540,15 +3476,11 @@
if (mDismissAllInProgress) {
// When dismissing all, we translate the entire view instead.
return super.getTranslation(v);
+ } else {
+ return ((ExpandableView) v).getTranslation();
}
- // All of the views in the list should have same translation, just use first one.
- if (mTranslatingViews.size() > 0) {
- return super.getTranslation(mTranslatingViews.get(0));
- }
- return 0;
}
-
/**
* Returns the horizontal space in pixels required to display the gear behind a
* notification.
@@ -3603,26 +3535,11 @@
final View prevGearExposedView = mGearExposedView;
mGearExposedView = null;
- AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
- public void onAnimationEnd(Animator animator) {
- if (prevGearExposedView instanceof ExpandableNotificationRow) {
- ((ExpandableNotificationRow) prevGearExposedView).getSettingsRow()
- .resetState();
- }
- }
- };
- AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- if (prevGearExposedView instanceof ExpandableNotificationRow) {
- ((ExpandableNotificationRow) prevGearExposedView)
- .setTranslationForOutline((float) animation.getAnimatedValue());
- }
- }
- };
- Animator set = getViewTranslationAnimator(prevGearExposedView, 0, updateListener);
- set.addListener(listener);
- set.start();
+ Animator anim = getViewTranslationAnimator(prevGearExposedView,
+ 0 /* leftTarget */, null /* updateListener */);
+ if (anim != null) {
+ anim.start();
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index eea923f..4c94fe9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -52,13 +52,8 @@
private StackIndentationFunctor mBottomStackIndentationFunctor;
private StackScrollAlgorithmState mTempAlgorithmState = new StackScrollAlgorithmState();
- private boolean mIsExpansionChanging;
- private int mFirstChildMaxHeight;
private boolean mIsExpanded;
- private ExpandableView mFirstChildWhileExpanding;
- private boolean mExpandedOnStart;
private int mBottomStackSlowDownLength;
- private int mCollapseSecondCardPadding;
public StackScrollAlgorithm(Context context) {
initView(context);
@@ -86,8 +81,6 @@
mZBasicHeight = (MAX_ITEMS_IN_BOTTOM_STACK + 1) * mZDistanceBetweenElements;
mBottomStackSlowDownLength = context.getResources()
.getDimensionPixelSize(R.dimen.bottom_stack_slow_down_length);
- mCollapseSecondCardPadding = context.getResources().getDimensionPixelSize(
- R.dimen.notification_collapse_second_card_padding);
mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
MAX_ITEMS_IN_BOTTOM_STACK,
mBottomStackPeekSize,
@@ -508,7 +501,7 @@
int childHeight, int minHeight, AmbientState ambientState) {
int bottomStackStart = ambientState.getInnerHeight()
- - mBottomStackPeekSize - mCollapseSecondCardPadding;
+ - mBottomStackPeekSize - mBottomStackSlowDownLength;
int childStart = bottomStackStart - childHeight;
if (childStart < childViewState.yTranslation) {
float newHeight = bottomStackStart - childViewState.yTranslation;
@@ -595,12 +588,9 @@
// The starting position of the bottom stack peek
int bottomPeekStart = ambientState.getInnerHeight() - mBottomStackPeekSize -
- mCollapseSecondCardPadding + ambientState.getScrollY();
+ mBottomStackSlowDownLength + ambientState.getScrollY();
// Collapse and expand the first child while the shade is being expanded
- float maxHeight = mIsExpansionChanging && child == mFirstChildWhileExpanding
- ? mFirstChildMaxHeight
- : childHeight;
- childViewState.height = (int) Math.max(Math.min(bottomPeekStart, maxHeight),
+ childViewState.height = (int) Math.max(Math.min(bottomPeekStart, (float) childHeight),
child.getMinHeight());
}
@@ -656,55 +646,6 @@
}
}
- public void onExpansionStarted(StackScrollState currentState) {
- mIsExpansionChanging = true;
- mExpandedOnStart = mIsExpanded;
- ViewGroup hostView = currentState.getHostView();
- updateFirstChildHeightWhileExpanding(hostView);
- }
-
- private void updateFirstChildHeightWhileExpanding(ViewGroup hostView) {
- mFirstChildWhileExpanding = (ExpandableView) findFirstVisibleChild(hostView);
- if (mFirstChildWhileExpanding != null) {
- if (mExpandedOnStart) {
-
- // We are collapsing the shade, so the first child can get as most as high as the
- // current height or the end value of the animation.
- mFirstChildMaxHeight = StackStateAnimator.getFinalActualHeight(
- mFirstChildWhileExpanding);
- } else {
- updateFirstChildMaxSizeToMaxHeight();
- }
- } else {
- mFirstChildMaxHeight = 0;
- }
- }
-
- private void updateFirstChildMaxSizeToMaxHeight() {
- // We are expanding the shade, expand it to its full height.
- if (!isMaxSizeInitialized(mFirstChildWhileExpanding)) {
-
- // This child was not layouted yet, wait for a layout pass
- mFirstChildWhileExpanding
- .addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right,
- int bottom, int oldLeft, int oldTop, int oldRight,
- int oldBottom) {
- if (mFirstChildWhileExpanding != null) {
- mFirstChildMaxHeight = getMaxAllowedChildHeight(
- mFirstChildWhileExpanding);
- } else {
- mFirstChildMaxHeight = 0;
- }
- v.removeOnLayoutChangeListener(this);
- }
- });
- } else {
- mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding);
- }
- }
-
private boolean isMaxSizeInitialized(ExpandableView child) {
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
@@ -724,32 +665,10 @@
return null;
}
- public void onExpansionStopped() {
- mIsExpansionChanging = false;
- mFirstChildWhileExpanding = null;
- }
-
public void setIsExpanded(boolean isExpanded) {
this.mIsExpanded = isExpanded;
}
- public void notifyChildrenChanged(final NotificationStackScrollLayout hostView) {
- if (mIsExpansionChanging) {
- hostView.post(new Runnable() {
- @Override
- public void run() {
- updateFirstChildHeightWhileExpanding(hostView);
- }
- });
- }
- }
-
- public void onReset(ExpandableView view) {
- if (view.equals(mFirstChildWhileExpanding)) {
- updateFirstChildMaxSizeToMaxHeight();
- }
- }
-
class StackScrollAlgorithmState {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 0ed6ef8..2524e1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -125,7 +125,7 @@
}
@Override
- protected boolean isPanelFullyCollapsed() {
+ public boolean isPanelFullyCollapsed() {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java b/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
index 61135bd..26e1d46 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
@@ -20,6 +20,8 @@
import android.provider.Settings;
import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.Prefs;
+import com.android.systemui.Prefs.Key;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.NightModeController;
@@ -46,6 +48,12 @@
}
@Override
+ public boolean isAvailable() {
+ return Prefs.getBoolean(mContext, Key.QS_NIGHT_ADDED, false)
+ && TunerService.isTunerEnabled(mContext);
+ }
+
+ @Override
public void setListening(boolean listening) {
if (listening) {
mNightModeController.addListener(this);
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
index fd753e9..285dfd1 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -50,6 +50,7 @@
private TextView mPlayPauseDescriptionTextView;
private View mCloseButtonView;
private View mCloseDescriptionView;
+ private boolean mPipMovedToFullscreen;
private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
@Override
@@ -69,6 +70,7 @@
@Override
public void onClick(View v) {
mPipManager.movePipToFullscreen();
+ mPipMovedToFullscreen = true;
finish();
}
});
@@ -167,7 +169,9 @@
}
private void restorePipAndFinish() {
- mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
+ if (!mPipMovedToFullscreen) {
+ mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
+ }
finish();
}
@@ -221,7 +225,7 @@
@Override
public void finish() {
super.finish();
- if (mPipManager.isRecentsShown()) {
+ if (mPipManager.isRecentsShown() && !mPipMovedToFullscreen) {
SystemUI[] services = ((SystemUIApplication) getApplication()).getServices();
for (int i = services.length - 1; i >= 0; i--) {
if (services[i] instanceof Recents) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index ebd5384..60d33fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -32,6 +32,7 @@
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
import org.mockito.ArgumentCaptor;
@@ -100,7 +101,7 @@
// Trigger blank callbacks to always get the current state (some tests don't trigger
// changes from default state).
- mNetworkController.addSignalCallback(null);
+ mNetworkController.addSignalCallback(mock(SignalCallback.class));
mNetworkController.addEmergencyListener(null);
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 5d693c9..f3140d2 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -1798,38 +1798,56 @@
// ACTION: User tapped notification action to cancel a bug report
// CATEGORY: NOTIFICATION
+ // OS: N
+ // GMS: 7.8.99
ACTION_BUGREPORT_NOTIFICATION_ACTION_CANCEL = 296;
// ACTION: User tapped notification action to launch bug report details screen
// CATEGORY: NOTIFICATION
+ // OS: N
+ // GMS: 7.8.99
ACTION_BUGREPORT_NOTIFICATION_ACTION_DETAILS = 297;
// ACTION: User tapped notification action to take adition screenshot on bug report
// CATEGORY: NOTIFICATION
+ // OS: N
+ // GMS: 7.8.99
ACTION_BUGREPORT_NOTIFICATION_ACTION_SCREENSHOT = 298;
// ACTION: User tapped notification to share bug report
// CATEGORY: NOTIFICATION
+ // OS: N
+ // GMS: 7.8.99
ACTION_BUGREPORT_NOTIFICATION_ACTION_SHARE = 299;
// ACTION: User changed bug report name using the details screen
// CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
ACTION_BUGREPORT_DETAILS_NAME_CHANGED = 300;
// ACTION: User changed bug report title using the details screen
// CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
ACTION_BUGREPORT_DETAILS_TITLE_CHANGED = 301;
// ACTION: User changed bug report description using the details screen
// CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
ACTION_BUGREPORT_DETAILS_DESCRIPTION_CHANGED = 302;
// ACTION: User tapped Save in the bug report details screen.
// CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
ACTION_BUGREPORT_DETAILS_SAVED = 303;
// ACTION: User tapped Cancel in the bug report details screen.
// CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
ACTION_BUGREPORT_DETAILS_CANCELED = 304;
// Tuner: Open/close calibrate dialog.
@@ -1927,6 +1945,14 @@
// access before; action pass package name of calling package.
ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_PACKAGE = 331;
+ // Logged when the user slides a notification and
+ // reveals the gear beneath it.
+ ACTION_REVEAL_GEAR = 332;
+
+ // Logged when the user taps on the gear beneath
+ // a notification.
+ ACTION_TOUCH_GEAR = 333;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index 8c78a3a..fc92966 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -115,7 +115,7 @@
if (cmp == Short.TYPE) {
if (checkType) {
- validateIsInt16();
+ validateIsInt16OrFloat16();
return mType.mElement.mType;
}
return Element.DataType.SIGNED_16;
@@ -402,9 +402,10 @@
"32 bit integer source does not match allocation type " + mType.mElement.mType);
}
- private void validateIsInt16() {
+ private void validateIsInt16OrFloat16() {
if ((mType.mElement.mType == Element.DataType.SIGNED_16) ||
- (mType.mElement.mType == Element.DataType.UNSIGNED_16)) {
+ (mType.mElement.mType == Element.DataType.UNSIGNED_16) ||
+ (mType.mElement.mType == Element.DataType.FLOAT_16)) {
return;
}
throw new RSIllegalArgumentException(
@@ -751,7 +752,7 @@
* @param d the source data array
*/
public void copyFrom(short[] d) {
- validateIsInt16();
+ validateIsInt16OrFloat16();
copyFromUnchecked(d, Element.DataType.SIGNED_16, d.length);
}
@@ -1060,7 +1061,7 @@
* @param d the source data array
*/
public void copy1DRangeFrom(int off, int count, short[] d) {
- validateIsInt16();
+ validateIsInt16OrFloat16();
copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
}
@@ -1204,7 +1205,7 @@
* @param data to be placed into the Allocation
*/
public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
- validateIsInt16();
+ validateIsInt16OrFloat16();
copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
Element.DataType.SIGNED_16, data.length);
}
@@ -1473,7 +1474,7 @@
* @param d The array to be set from the Allocation.
*/
public void copyTo(short[] d) {
- validateIsInt16();
+ validateIsInt16OrFloat16();
copyTo(d, Element.DataType.SIGNED_16, d.length);
}
@@ -1693,7 +1694,7 @@
* @param d the source data array
*/
public void copy1DRangeTo(int off, int count, short[] d) {
- validateIsInt16();
+ validateIsInt16OrFloat16();
copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
}
@@ -1794,7 +1795,7 @@
* @param data Dest Array to be copied into
*/
public void copy2DRangeTo(int xoff, int yoff, int w, int h, short[] data) {
- validateIsInt16();
+ validateIsInt16OrFloat16();
copy2DRangeToUnchecked(xoff, yoff, w, h, data,
Element.DataType.SIGNED_16, data.length);
}
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 3bef19e..4877a378 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -151,6 +151,7 @@
return; \
case RS_TYPE_SIGNED_16: \
case RS_TYPE_UNSIGNED_16: \
+ case RS_TYPE_FLOAT_16: \
len = _env->GetArrayLength((jshortArray)data); \
ptr = _env->GetShortArrayElements((jshortArray)data, flag); \
if (ptr == nullptr) { \
@@ -1061,7 +1062,7 @@
type, kind, norm, size);
}
return (jlong)(uintptr_t)rsElementCreate((RsContext)con, (RsDataType)type, (RsDataKind)kind,
- norm, size);
+ norm, size, true);
}
static jlong
@@ -1100,7 +1101,7 @@
jlong id = (jlong)(uintptr_t)rsElementCreate2((RsContext)con,
(const RsElement *)ids, fieldCount,
nameArray, fieldCount * sizeof(size_t), sizeArray,
- (const uint32_t *)arraySizes, fieldCount);
+ (const uint32_t *)arraySizes, fieldCount, true);
free(ids);
free(arraySizes);
@@ -1174,7 +1175,7 @@
}
return (jlong)(uintptr_t)rsTypeCreate((RsContext)con, (RsElement)eid, dimx, dimy, dimz, mips,
- faces, yuv);
+ faces, yuv, true);
}
static void
@@ -1210,7 +1211,7 @@
}
return (jlong)(uintptr_t) rsAllocationCreateTyped((RsContext)con, (RsType)type,
(RsAllocationMipmapControl)mips,
- (uint32_t)usage, (uintptr_t)pointer);
+ (uint32_t)usage, (uintptr_t)pointer, true);
}
static void
@@ -1315,7 +1316,7 @@
const void* ptr = bitmap.getPixels();
jlong id = (jlong)(uintptr_t)rsAllocationCreateFromBitmap((RsContext)con,
(RsType)type, (RsAllocationMipmapControl)mip,
- ptr, bitmap.getSize(), usage);
+ ptr, bitmap.getSize(), usage, true);
bitmap.unlockPixels();
return id;
}
@@ -1331,7 +1332,7 @@
const void* ptr = bitmap.getPixels();
jlong id = (jlong)(uintptr_t)rsAllocationCreateTyped((RsContext)con,
(RsType)type, (RsAllocationMipmapControl)mip,
- (uint32_t)usage, (uintptr_t)ptr);
+ (uint32_t)usage, (uintptr_t)ptr, true);
bitmap.unlockPixels();
return id;
}
@@ -1347,7 +1348,7 @@
const void* ptr = bitmap.getPixels();
jlong id = (jlong)(uintptr_t)rsAllocationCubeCreateFromBitmap((RsContext)con,
(RsType)type, (RsAllocationMipmapControl)mip,
- ptr, bitmap.getSize(), usage);
+ ptr, bitmap.getSize(), usage, true);
bitmap.unlockPixels();
return id;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index acd57b17..9e6c21c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -655,10 +655,9 @@
userState.mUiAutomationServiceOwner = owner;
userState.mUiAutomationServiceClient = serviceClient;
userState.mUiAutomationFlags = flags;
- userState.mIsAccessibilityEnabled = true;
userState.mInstalledServices.add(accessibilityServiceInfo);
if ((flags & UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES) == 0) {
- // Set the temporary state.
+ // Set the temporary state, and use it instead of settings
userState.mIsTouchExplorationEnabled = false;
userState.mIsEnhancedWebAccessibilityEnabled = false;
userState.mIsDisplayMagnificationEnabled = false;
@@ -709,7 +708,6 @@
return;
}
- userState.mIsAccessibilityEnabled = true;
userState.mIsTouchExplorationEnabled = touchExplorationEnabled;
userState.mIsEnhancedWebAccessibilityEnabled = false;
userState.mIsDisplayMagnificationEnabled = false;
@@ -1245,17 +1243,17 @@
}
}
- private void manageServicesLocked(UserState userState) {
+ private void updateServicesLocked(UserState userState) {
Map<ComponentName, Service> componentNameToServiceMap =
userState.mComponentNameToServiceMap;
boolean isUnlocked = mContext.getSystemService(UserManager.class)
.isUserUnlocked(userState.mUserId);
- boolean isEnabled = userState.mIsAccessibilityEnabled;
for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
ComponentName componentName = ComponentName.unflattenFromString(
installedService.getId());
+
Service service = componentNameToServiceMap.get(componentName);
// Ignore non-encryption-aware services until user is unlocked
@@ -1264,45 +1262,25 @@
continue;
}
- if (isEnabled) {
- // Wait for the binding if it is in process.
- if (userState.mBindingServices.contains(componentName)) {
+ // Wait for the binding if it is in process.
+ if (userState.mBindingServices.contains(componentName)) {
+ continue;
+ }
+ if (userState.mEnabledServices.contains(componentName)) {
+ if (service == null) {
+ service = new Service(userState.mUserId, componentName, installedService);
+ } else if (userState.mBoundServices.contains(service)) {
continue;
}
- if (userState.mEnabledServices.contains(componentName)) {
- if (service == null) {
- service = new Service(userState.mUserId, componentName, installedService);
- } else if (userState.mBoundServices.contains(service)) {
- continue;
- }
- service.bindLocked();
- } else {
- if (service != null) {
- service.unbindLocked();
- }
- }
+ service.bindLocked();
} else {
if (service != null) {
service.unbindLocked();
- } else {
- userState.mBindingServices.remove(componentName);
}
}
}
- // No enabled installed services => disable accessibility to avoid
- // sending accessibility events with no recipient across processes.
- if (isEnabled && isUnlocked && userState.mBoundServices.isEmpty()
- && userState.mBindingServices.isEmpty()) {
- userState.mIsAccessibilityEnabled = false;
- final long identity = Binder.clearCallingIdentity();
- try {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
+ updateAccessibilityEnabledSetting(userState);
}
private void scheduleUpdateClientsIfNeededLocked(UserState userState) {
@@ -1329,7 +1307,8 @@
flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
}
// Touch exploration without accessibility makes no sense.
- if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) {
+ if (userState.isHandlingAccessibilityEvents()
+ && userState.mIsTouchExplorationEnabled) {
flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
}
if (userState.mIsFilterKeyEventsEnabled) {
@@ -1468,25 +1447,17 @@
}
private void updateWindowsForAccessibilityCallbackLocked(UserState userState) {
- if (userState.mIsAccessibilityEnabled) {
- // We observe windows for accessibility only if there is at least
- // one bound service that can retrieve window content that specified
- // it is interested in accessing such windows. For services that are
- // binding we do an update pass after each bind event, so we run this
- // code and register the callback if needed.
- boolean boundServiceCanRetrieveInteractiveWindows = false;
+ // We observe windows for accessibility only if there is at least
+ // one bound service that can retrieve window content that specified
+ // it is interested in accessing such windows. For services that are
+ // binding we do an update pass after each bind event, so we run this
+ // code and register the callback if needed.
- List<Service> boundServices = userState.mBoundServices;
- final int boundServiceCount = boundServices.size();
- for (int i = 0; i < boundServiceCount; i++) {
- Service boundService = boundServices.get(i);
- if (boundService.canRetrieveInteractiveWindowsLocked()) {
- boundServiceCanRetrieveInteractiveWindows = true;
- break;
- }
- }
-
- if (boundServiceCanRetrieveInteractiveWindows) {
+ List<Service> boundServices = userState.mBoundServices;
+ final int boundServiceCount = boundServices.size();
+ for (int i = 0; i < boundServiceCount; i++) {
+ Service boundService = boundServices.get(i);
+ if (boundService.canRetrieveInteractiveWindowsLocked()) {
if (mWindowsForAccessibilityCallback == null) {
mWindowsForAccessibilityCallback = new WindowsForAccessibilityCallback();
mWindowManagerService.setWindowsForAccessibilityCallback(
@@ -1554,37 +1525,30 @@
userState.mIsFilterKeyEventsEnabled = false;
}
- private void updateServicesLocked(UserState userState) {
- if (userState.mIsAccessibilityEnabled) {
- manageServicesLocked(userState);
- } else {
- unbindAllServicesLocked(userState);
- }
- }
-
private boolean readConfigurationForUserStateLocked(UserState userState) {
- boolean somthingChanged = readAccessibilityEnabledSettingLocked(userState);
- somthingChanged |= readInstalledAccessibilityServiceLocked(userState);
- somthingChanged |= readEnabledAccessibilityServicesLocked(userState);
- somthingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState);
- somthingChanged |= readTouchExplorationEnabledSettingLocked(userState);
- somthingChanged |= readHighTextContrastEnabledSettingLocked(userState);
- somthingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
- somthingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
- somthingChanged |= readAutoclickEnabledSettingLocked(userState);
- somthingChanged |= readDisplayColorAdjustmentSettingsLocked(userState);
- return somthingChanged;
+ boolean somethingChanged = readInstalledAccessibilityServiceLocked(userState);
+ somethingChanged |= readEnabledAccessibilityServicesLocked(userState);
+ somethingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState);
+ somethingChanged |= readTouchExplorationEnabledSettingLocked(userState);
+ somethingChanged |= readHighTextContrastEnabledSettingLocked(userState);
+ somethingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
+ somethingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
+ somethingChanged |= readAutoclickEnabledSettingLocked(userState);
+ somethingChanged |= readDisplayColorAdjustmentSettingsLocked(userState);
+
+ return somethingChanged;
}
- private boolean readAccessibilityEnabledSettingLocked(UserState userState) {
- final boolean accessibilityEnabled = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1;
- if (accessibilityEnabled != userState.mIsAccessibilityEnabled) {
- userState.mIsAccessibilityEnabled = accessibilityEnabled;
- return true;
+ private void updateAccessibilityEnabledSetting(UserState userState) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED,
+ userState.isHandlingAccessibilityEvents() ? 0 : 1,
+ userState.mUserId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- return false;
}
private boolean readTouchExplorationEnabledSettingLocked(UserState userState) {
@@ -1809,7 +1773,7 @@
// Check whether any Accessibility Services are still enabled and, if not, remove flag
// requesting no soft keyboard
final boolean accessibilityRequestingNoIme = userState.mSoftKeyboardShowMode == 1;
- if (accessibilityRequestingNoIme && !userState.mIsAccessibilityEnabled) {
+ if (accessibilityRequestingNoIme && !userState.isHandlingAccessibilityEvents()) {
// No active Accessibility Services can be requesting the soft keyboard to be hidden
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
@@ -1853,7 +1817,6 @@
UserState userState = mUserStates.valueAt(i);
pw.append("User state[attributes:{id=" + userState.mUserId);
pw.append(", currentUser=" + (userState.mUserId == mCurrentUserId));
- pw.append(", accessibilityEnabled=" + userState.mIsAccessibilityEnabled);
pw.append(", touchExplorationEnabled=" + userState.mIsTouchExplorationEnabled);
pw.append(", displayMagnificationEnabled="
+ userState.mIsDisplayMagnificationEnabled);
@@ -2003,7 +1966,7 @@
private void announceNewUserIfNeeded() {
synchronized (mLock) {
UserState userState = getCurrentUserStateLocked();
- if (userState.mIsAccessibilityEnabled) {
+ if (userState.isHandlingAccessibilityEvents()) {
UserManager userManager = (UserManager) mContext.getSystemService(
Context.USER_SERVICE);
String message = mContext.getString(R.string.user_switched,
@@ -4061,7 +4024,6 @@
public int mSoftKeyboardShowMode = 0;
- public boolean mIsAccessibilityEnabled;
public boolean mIsTouchExplorationEnabled;
public boolean mIsTextHighContrastEnabled;
public boolean mIsEnhancedWebAccessibilityEnabled;
@@ -4096,11 +4058,11 @@
public int getClientState() {
int clientState = 0;
- if (mIsAccessibilityEnabled) {
+ if (isHandlingAccessibilityEvents()) {
clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
}
// Touch exploration relies on enabled accessibility.
- if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) {
+ if (isHandlingAccessibilityEvents() && mIsTouchExplorationEnabled) {
clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
}
if (mIsTextHighContrastEnabled) {
@@ -4109,6 +4071,10 @@
return clientState;
}
+ public boolean isHandlingAccessibilityEvents() {
+ return !mBoundServices.isEmpty() || !mBoundServices.isEmpty();
+ }
+
public void onSwitchToAnotherUser() {
// Clear UI test automation state.
if (mUiAutomationService != null) {
@@ -4128,7 +4094,6 @@
// Clear state persisted in settings.
mEnabledServices.clear();
mTouchExplorationGrantedServices.clear();
- mIsAccessibilityEnabled = false;
mIsTouchExplorationEnabled = false;
mIsEnhancedWebAccessibilityEnabled = false;
mIsDisplayMagnificationEnabled = false;
@@ -4155,9 +4120,6 @@
private final class AccessibilityContentObserver extends ContentObserver {
- private final Uri mAccessibilityEnabledUri = Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_ENABLED);
-
private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor(
Settings.Secure.TOUCH_EXPLORATION_ENABLED);
@@ -4199,8 +4161,6 @@
}
public void register(ContentResolver contentResolver) {
- contentResolver.registerContentObserver(mAccessibilityEnabledUri,
- false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(mTouchExplorationEnabledUri,
false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri,
@@ -4240,11 +4200,7 @@
return;
}
- if (mAccessibilityEnabledUri.equals(uri)) {
- if (readAccessibilityEnabledSettingLocked(userState)) {
- onUserStateChangedLocked(userState);
- }
- } else if (mTouchExplorationEnabledUri.equals(uri)) {
+ if (mTouchExplorationEnabledUri.equals(uri)) {
if (readTouchExplorationEnabledSettingLocked(userState)) {
onUserStateChangedLocked(userState);
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index f1a9c44..cd4d107d 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -3495,9 +3495,8 @@
// The agent was running with a stub Application object, so shut it down.
// !!! We hardcode the confirmation UI's package name here rather than use a
// manifest flag! TODO something less direct.
- if (app.uid != Process.SYSTEM_UID
- && !app.packageName.equals("com.android.backupconfirm")
- && app.uid != Process.PHONE_UID) {
+ if (app.uid >= Process.FIRST_APPLICATION_UID
+ && !app.packageName.equals("com.android.backupconfirm")) {
if (MORE_DEBUG) Slog.d(TAG, "Killing agent host process");
mActivityManager.killApplicationProcess(app.processName, app.uid);
} else {
@@ -6881,7 +6880,7 @@
// The agent was running with a stub Application object, so shut it down.
// !!! We hardcode the confirmation UI's package name here rather than use a
// manifest flag! TODO something less direct.
- if (app.uid != Process.SYSTEM_UID
+ if (app.uid >= Process.FIRST_APPLICATION_UID
&& !app.packageName.equals("com.android.backupconfirm")) {
if (DEBUG) Slog.d(TAG, "Killing host process");
mActivityManager.killApplicationProcess(app.processName, app.uid);
@@ -8625,13 +8624,15 @@
// it is explicitly not killed following that operation.
//
// We execute this kill when these conditions hold:
- // 1. the app did not request its own restore (mTargetPackage == null), and either
- // 2a. the app is a full-data target (TYPE_FULL_STREAM) or
+ // 1. it's not a system-uid process,
+ // 2. the app did not request its own restore (mTargetPackage == null), and either
+ // 3a. the app is a full-data target (TYPE_FULL_STREAM) or
// b. the app does not state android:killAfterRestore="false" in its manifest
final int appFlags = mCurrentPackage.applicationInfo.flags;
final boolean killAfterRestore =
- (mRestoreDescription.getDataType() == RestoreDescription.TYPE_FULL_STREAM)
- || ((appFlags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0);
+ (mCurrentPackage.applicationInfo.uid >= Process.FIRST_APPLICATION_UID)
+ && ((mRestoreDescription.getDataType() == RestoreDescription.TYPE_FULL_STREAM)
+ || ((appFlags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0));
if (mTargetPackage == null && killAfterRestore) {
if (DEBUG) Slog.d(TAG, "Restore complete, killing host process of "
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 25b6fdd..86040c2 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -125,6 +125,7 @@
import com.android.server.connectivity.NetworkMonitor;
import com.android.server.connectivity.PacManager;
import com.android.server.connectivity.PermissionMonitor;
+import com.android.server.connectivity.ApfFilter;
import com.android.server.connectivity.Tethering;
import com.android.server.connectivity.Vpn;
import com.android.server.net.BaseNetworkObserver;
@@ -163,7 +164,7 @@
implements PendingIntent.OnFinished {
private static final String TAG = "ConnectivityService";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean VDBG = false;
private static final boolean LOGD_RULES = false;
@@ -353,6 +354,13 @@
*/
private static final int EVENT_REGISTER_NETWORK_LISTENER_WITH_INTENT = 31;
+ /**
+ * used to push APF program to NetworkAgent
+ * replyTo = NetworkAgent message handler
+ * obj = byte[] of APF program
+ */
+ private static final int EVENT_PUSH_APF_PROGRAM_TO_NETWORK = 32;
+
/** Handler thread used for both of the handlers below. */
@VisibleForTesting
protected final HandlerThread mHandlerThread;
@@ -447,7 +455,7 @@
*/
private class LegacyTypeTracker {
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean VDBG = false;
private static final String TAG = "CSLegacyTypeTracker";
@@ -2190,6 +2198,7 @@
mKeepaliveTracker.handleStopAllKeepalives(nai,
ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
+ if (nai.apfFilter != null) nai.apfFilter.shutdown();
mNetworkAgentInfos.remove(msg.replyTo);
updateClat(null, nai.linkProperties, nai);
synchronized (mNetworkForNetId) {
@@ -2404,6 +2413,13 @@
accept ? 1 : 0, always ? 1: 0, network));
}
+ public void pushApfProgramToNetwork(NetworkAgentInfo nai, byte[] program) {
+ enforceConnectivityInternalPermission();
+ Message msg = mHandler.obtainMessage(EVENT_PUSH_APF_PROGRAM_TO_NETWORK, program);
+ msg.replyTo = nai.messenger;
+ mHandler.sendMessage(msg);
+ }
+
private void handleSetAcceptUnvalidated(Network network, boolean accept, boolean always) {
if (DBG) log("handleSetAcceptUnvalidated network=" + network +
" accept=" + accept + " always=" + always);
@@ -2553,6 +2569,16 @@
handleMobileDataAlwaysOn();
break;
}
+ case EVENT_PUSH_APF_PROGRAM_TO_NETWORK: {
+ NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
+ if (nai == null) {
+ loge("EVENT_PUSH_APF_PROGRAM_TO_NETWORK from unknown NetworkAgent");
+ } else {
+ nai.asyncChannel.sendMessage(NetworkAgent.CMD_PUSH_APF_PROGRAM,
+ (byte[]) msg.obj);
+ }
+ break;
+ }
// Sent by KeepaliveTracker to process an app request on the state machine thread.
case NetworkAgent.CMD_START_PACKET_KEEPALIVE: {
mKeepaliveTracker.handleStartKeepalive(msg);
@@ -4068,6 +4094,9 @@
if (networkAgent.clatd != null) {
networkAgent.clatd.fixupLinkProperties(oldLp);
}
+ if (networkAgent.apfFilter != null) {
+ networkAgent.apfFilter.updateFilter();
+ }
updateInterfaces(newLp, oldLp, netId);
updateMtu(newLp, oldLp);
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 63c9822..3b6c62b 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -1960,14 +1960,6 @@
throw new IllegalArgumentException("Unknown id: " + id);
}
- if (mCurClient != null && mCurAttribute != null) {
- // We have already made sure that the package name belongs to the application's UID.
- // No further UID check is required.
- if (SystemConfig.getInstance().getFixedImeApps().contains(mCurAttribute.packageName)) {
- return;
- }
- }
-
// See if we need to notify a subtype change within the same IME.
if (id.equals(mCurMethodId)) {
final int subtypeCount = info.getSubtypeCount();
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index ba2a2e0..6fb0671 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -345,9 +345,9 @@
final int userId = users.get(user).id;
final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
- if (ownerInfo != null) {
+ if (!TextUtils.isEmpty(ownerInfo)) {
setString(OWNER_INFO, ownerInfo, userId);
- Settings.Secure.putStringForUser(cr, ownerInfo, "", userId);
+ Settings.Secure.putStringForUser(cr, OWNER_INFO, "", userId);
}
// Migrate owner info enabled. Note there was a bug where older platforms only
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 799d0bd..329f716 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -22,8 +22,10 @@
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_NONE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.FIREWALL_TYPE_BLACKLIST;
@@ -43,7 +45,6 @@
import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsListResult;
import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
-
import android.annotation.NonNull;
import android.app.ActivityManagerNative;
import android.content.Context;
@@ -226,6 +227,12 @@
*/
@GuardedBy("mQuotaLock")
private SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
+ /**
+ * Set of UIDs that are to be blocked/allowed by firewall controller. This set of Ids matches
+ * to device on power-save mode.
+ */
+ @GuardedBy("mQuotaLock")
+ private SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
/** Set of states for the child firewall chains. True if the chain is active. */
@GuardedBy("mQuotaLock")
final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
@@ -286,8 +293,8 @@
Watchdog.getInstance().addMonitor(this);
}
- static NetworkManagementService create(Context context,
- String socket) throws InterruptedException {
+ static NetworkManagementService create(Context context, String socket)
+ throws InterruptedException {
final NetworkManagementService service = new NetworkManagementService(context, socket);
final CountDownLatch connectedSignal = service.mConnectedSignal;
if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
@@ -303,8 +310,15 @@
}
public void systemReady() {
- prepareNativeDaemon();
- if (DBG) Slog.d(TAG, "Prepared");
+ if (DBG) {
+ final long start = System.currentTimeMillis();
+ prepareNativeDaemon();
+ final long delta = System.currentTimeMillis() - start;
+ Slog.d(TAG, "Prepared in " + delta + "ms");
+ return;
+ } else {
+ prepareNativeDaemon();
+ }
}
private IBatteryStats getBatteryStats() {
@@ -339,8 +353,7 @@
for (int i = 0; i < length; i++) {
try {
mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ } catch (RemoteException | RuntimeException e) {
}
}
} finally {
@@ -358,8 +371,7 @@
for (int i = 0; i < length; i++) {
try {
mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ } catch (RemoteException | RuntimeException e) {
}
}
} finally {
@@ -376,8 +388,7 @@
for (int i = 0; i < length; i++) {
try {
mObservers.getBroadcastItem(i).interfaceAdded(iface);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ } catch (RemoteException | RuntimeException e) {
}
}
} finally {
@@ -399,8 +410,7 @@
for (int i = 0; i < length; i++) {
try {
mObservers.getBroadcastItem(i).interfaceRemoved(iface);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ } catch (RemoteException | RuntimeException e) {
}
}
} finally {
@@ -417,8 +427,7 @@
for (int i = 0; i < length; i++) {
try {
mObservers.getBroadcastItem(i).limitReached(limitName, iface);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ } catch (RemoteException | RuntimeException e) {
}
}
} finally {
@@ -476,8 +485,7 @@
try {
mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(
Integer.toString(type), isActive, tsNanos);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ } catch (RemoteException | RuntimeException e) {
}
}
} finally {
@@ -520,7 +528,7 @@
Log.wtf(TAG, "problem enabling bandwidth controls", e);
}
} else {
- Slog.d(TAG, "not enabling bandwidth control");
+ Slog.i(TAG, "not enabling bandwidth control");
}
SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
@@ -543,7 +551,7 @@
synchronized (mQuotaLock) {
int size = mActiveQuotas.size();
if (size > 0) {
- Slog.d(TAG, "Pushing " + size + " active quota rules");
+ if (DBG) Slog.d(TAG, "Pushing " + size + " active quota rules");
final HashMap<String, Long> activeQuotas = mActiveQuotas;
mActiveQuotas = Maps.newHashMap();
for (Map.Entry<String, Long> entry : activeQuotas.entrySet()) {
@@ -553,7 +561,7 @@
size = mActiveAlerts.size();
if (size > 0) {
- Slog.d(TAG, "Pushing " + size + " active alert rules");
+ if (DBG) Slog.d(TAG, "Pushing " + size + " active alert rules");
final HashMap<String, Long> activeAlerts = mActiveAlerts;
mActiveAlerts = Maps.newHashMap();
for (Map.Entry<String, Long> entry : activeAlerts.entrySet()) {
@@ -563,7 +571,7 @@
size = mUidRejectOnQuota.size();
if (size > 0) {
- Slog.d(TAG, "Pushing " + size + " active UID rules");
+ if (DBG) Slog.d(TAG, "Pushing " + size + " active UID rules");
final SparseBooleanArray uidRejectOnQuota = mUidRejectOnQuota;
mUidRejectOnQuota = new SparseBooleanArray();
for (int i = 0; i < uidRejectOnQuota.size(); i++) {
@@ -573,7 +581,7 @@
size = mUidCleartextPolicy.size();
if (size > 0) {
- Slog.d(TAG, "Pushing " + size + " active UID cleartext policies");
+ if (DBG) Slog.d(TAG, "Pushing " + size + " active UID cleartext policies");
final SparseIntArray local = mUidCleartextPolicy;
mUidCleartextPolicy = new SparseIntArray();
for (int i = 0; i < local.size(); i++) {
@@ -585,7 +593,7 @@
size = mUidFirewallRules.size();
if (size > 0) {
- Slog.d(TAG, "Pushing " + size + " active firewall UID rules");
+ if (DBG) Slog.d(TAG, "Pushing " + size + " active firewall UID rules");
final SparseIntArray uidFirewallRules = mUidFirewallRules;
mUidFirewallRules = new SparseIntArray();
for (int i = 0; i < uidFirewallRules.size(); i++) {
@@ -596,7 +604,7 @@
size = mUidFirewallStandbyRules.size();
if (size > 0) {
- Slog.d(TAG, "Pushing " + size + " active firewall standby UID rules");
+ if (DBG) Slog.d(TAG, "Pushing " + size + " active firewall standby UID rules");
final SparseIntArray uidFirewallRules = mUidFirewallStandbyRules;
mUidFirewallStandbyRules = new SparseIntArray();
for (int i = 0; i < uidFirewallRules.size(); i++) {
@@ -610,7 +618,7 @@
size = mUidFirewallDozableRules.size();
if (size > 0) {
- Slog.d(TAG, "Pushing " + size + " active firewall dozable UID rules");
+ if (DBG) Slog.d(TAG, "Pushing " + size + " active firewall dozable UID rules");
final SparseIntArray uidFirewallRules = mUidFirewallDozableRules;
mUidFirewallDozableRules = new SparseIntArray();
for (int i = 0; i < uidFirewallRules.size(); i++) {
@@ -621,6 +629,20 @@
if (mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE)) {
setFirewallChainEnabled(FIREWALL_CHAIN_DOZABLE, true);
}
+
+ size = mUidFirewallPowerSaveRules.size();
+ if (size > 0) {
+ Slog.d(TAG, "Pushing " + size + " active firewall powersave UID rules");
+ final SparseIntArray uidFirewallRules = mUidFirewallPowerSaveRules;
+ mUidFirewallPowerSaveRules = new SparseIntArray();
+ for (int i = 0; i < uidFirewallRules.size(); i++) {
+ setFirewallUidRuleInternal(FIREWALL_CHAIN_POWERSAVE, uidFirewallRules.keyAt(i),
+ uidFirewallRules.valueAt(i));
+ }
+ }
+ if (mFirewallChainStates.get(FIREWALL_CHAIN_POWERSAVE)) {
+ setFirewallChainEnabled(FIREWALL_CHAIN_POWERSAVE, true);
+ }
}
}
@@ -633,8 +655,7 @@
for (int i = 0; i < length; i++) {
try {
mObservers.getBroadcastItem(i).addressUpdated(iface, address);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ } catch (RemoteException | RuntimeException e) {
}
}
} finally {
@@ -651,8 +672,7 @@
for (int i = 0; i < length; i++) {
try {
mObservers.getBroadcastItem(i).addressRemoved(iface, address);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ } catch (RemoteException | RuntimeException e) {
}
}
} finally {
@@ -670,8 +690,7 @@
try {
mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime,
addresses);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ } catch (RemoteException | RuntimeException e) {
}
}
} finally {
@@ -692,8 +711,7 @@
} else {
mObservers.getBroadcastItem(i).routeRemoved(route);
}
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ } catch (RemoteException | RuntimeException e) {
}
}
} finally {
@@ -1210,7 +1228,7 @@
// TODO: remove from aidl if nobody calls externally
mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG);
- Slog.d(TAG, "Shutting down");
+ Slog.i(TAG, "Shutting down");
}
@Override
@@ -2023,6 +2041,9 @@
case FIREWALL_CHAIN_DOZABLE:
chainName = FIREWALL_CHAIN_NAME_DOZABLE;
break;
+ case FIREWALL_CHAIN_POWERSAVE:
+ chainName = FIREWALL_CHAIN_NAME_POWERSAVE;
+ break;
default:
throw new IllegalArgumentException("Bad child chain: " + chain);
}
@@ -2039,6 +2060,8 @@
return FIREWALL_TYPE_BLACKLIST;
case FIREWALL_CHAIN_DOZABLE:
return FIREWALL_TYPE_WHITELIST;
+ case FIREWALL_CHAIN_POWERSAVE:
+ return FIREWALL_TYPE_WHITELIST;
default:
return isFirewallEnabled() ? FIREWALL_TYPE_WHITELIST : FIREWALL_TYPE_BLACKLIST;
}
@@ -2138,6 +2161,8 @@
return mUidFirewallStandbyRules;
case FIREWALL_CHAIN_DOZABLE:
return mUidFirewallDozableRules;
+ case FIREWALL_CHAIN_POWERSAVE:
+ return mUidFirewallPowerSaveRules;
case FIREWALL_CHAIN_NONE:
return mUidFirewallRules;
default:
@@ -2151,6 +2176,8 @@
return FIREWALL_CHAIN_NAME_STANDBY;
case FIREWALL_CHAIN_DOZABLE:
return FIREWALL_CHAIN_NAME_DOZABLE;
+ case FIREWALL_CHAIN_POWERSAVE:
+ return FIREWALL_CHAIN_NAME_POWERSAVE;
case FIREWALL_CHAIN_NONE:
return FIREWALL_CHAIN_NAME_NONE;
default:
@@ -2225,8 +2252,7 @@
for (int i = 0; i < length; i++) {
try {
mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ } catch (RemoteException | RuntimeException e) {
}
}
} finally {
@@ -2271,43 +2297,25 @@
}
synchronized (mUidFirewallRules) {
- pw.print("UID firewall rule: [");
- final int size = mUidFirewallRules.size();
- for (int i = 0; i < size; i++) {
- pw.print(mUidFirewallRules.keyAt(i));
- pw.print(":");
- pw.print(mUidFirewallRules.valueAt(i));
- if (i < size - 1) pw.print(",");
- }
- pw.println("]");
+ dumpUidFirewallRule(pw, "", mUidFirewallRules);
}
pw.println("UID firewall standby chain enabled: " +
mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY));
synchronized (mUidFirewallStandbyRules) {
- pw.print("UID firewall standby rule: [");
- final int size = mUidFirewallStandbyRules.size();
- for (int i = 0; i < size; i++) {
- pw.print(mUidFirewallStandbyRules.keyAt(i));
- pw.print(":");
- pw.print(mUidFirewallStandbyRules.valueAt(i));
- if (i < size - 1) pw.print(",");
- }
- pw.println("]");
+ dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_STANDBY, mUidFirewallStandbyRules);
}
pw.println("UID firewall dozable chain enabled: " +
mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE));
synchronized (mUidFirewallDozableRules) {
- pw.print("UID firewall dozable rule: [");
- final int size = mUidFirewallDozableRules.size();
- for (int i = 0; i < size; i++) {
- pw.print(mUidFirewallDozableRules.keyAt(i));
- pw.print(":");
- pw.print(mUidFirewallDozableRules.valueAt(i));
- if (i < size - 1) pw.print(",");
- }
- pw.println("]");
+ dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_DOZABLE, mUidFirewallDozableRules);
+ }
+
+ pw.println("UID firewall powersave chain enabled: " +
+ mFirewallChainStates.get(FIREWALL_CHAIN_POWERSAVE));
+ synchronized (mUidFirewallPowerSaveRules) {
+ dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_POWERSAVE, mUidFirewallPowerSaveRules);
}
synchronized (mIdleTimerLock) {
@@ -2324,6 +2332,20 @@
pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
}
+ private void dumpUidFirewallRule(PrintWriter pw, String name, SparseIntArray rules) {
+ pw.print("UID firewall");
+ pw.print(name);
+ pw.print(" rule: [");
+ final int size = rules.size();
+ for (int i = 0; i < size; i++) {
+ pw.print(rules.keyAt(i));
+ pw.print(":");
+ pw.print(rules.valueAt(i));
+ if (i < size - 1) pw.print(",");
+ }
+ pw.println("]");
+ }
+
@Override
public void createPhysicalNetwork(int netId, String permission) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index f4c6225..11aef17 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -58,7 +58,7 @@
private static final String TAG = "NsdService";
private static final String MDNS_TAG = "mDnsConnector";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private Context mContext;
private ContentResolver mContentResolver;
diff --git a/services/core/java/com/android/server/RecoverySystemService.java b/services/core/java/com/android/server/RecoverySystemService.java
index d237fe7..d284d07 100644
--- a/services/core/java/com/android/server/RecoverySystemService.java
+++ b/services/core/java/com/android/server/RecoverySystemService.java
@@ -17,6 +17,8 @@
package com.android.server;
import android.content.Context;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
import android.os.IRecoverySystem;
import android.os.IRecoverySystemProgressListener;
import android.os.RecoverySystem;
@@ -26,9 +28,11 @@
import android.system.Os;
import android.util.Slog;
-import java.io.BufferedReader;
+import libcore.io.IoUtils;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
import java.io.File;
-import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
@@ -43,10 +47,10 @@
private static final String TAG = "RecoverySystemService";
private static final boolean DEBUG = false;
- // A pipe file to monitor the uncrypt progress.
- private static final String UNCRYPT_STATUS_FILE = "/cache/recovery/uncrypt_status";
- // Temporary command file to communicate between the system server and uncrypt.
- private static final String COMMAND_FILE = "/cache/recovery/command";
+ // The socket at /dev/socket/uncrypt to communicate with uncrypt.
+ private static final String UNCRYPT_SOCKET = "uncrypt";
+
+ private static final int SOCKET_CONNECTION_MAX_RETRY = 30;
private Context mContext;
@@ -79,60 +83,63 @@
return false;
}
- // Create the status pipe file to communicate with uncrypt.
- new File(UNCRYPT_STATUS_FILE).delete();
- try {
- Os.mkfifo(UNCRYPT_STATUS_FILE, 0600);
- } catch (ErrnoException e) {
- Slog.e(TAG, "ErrnoException when creating named pipe \"" + UNCRYPT_STATUS_FILE +
- "\": " + e.getMessage());
- return false;
- }
-
// Trigger uncrypt via init.
SystemProperties.set("ctl.start", "uncrypt");
- // Read the status from the pipe.
- try (BufferedReader reader = new BufferedReader(new FileReader(UNCRYPT_STATUS_FILE))) {
+ // Connect to the uncrypt service socket.
+ LocalSocket socket = connectService();
+ if (socket == null) {
+ Slog.e(TAG, "Failed to connect to uncrypt socket");
+ return false;
+ }
+
+ // Read the status from the socket.
+ try (DataInputStream dis = new DataInputStream(socket.getInputStream());
+ DataOutputStream dos = new DataOutputStream(socket.getOutputStream())) {
int lastStatus = Integer.MIN_VALUE;
while (true) {
- String str = reader.readLine();
- try {
- int status = Integer.parseInt(str);
+ int status = dis.readInt();
+ // Avoid flooding the log with the same message.
+ if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
+ continue;
+ }
+ lastStatus = status;
- // Avoid flooding the log with the same message.
- if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
- continue;
- }
- lastStatus = status;
-
- if (status >= 0 && status <= 100) {
- // Update status
- Slog.i(TAG, "uncrypt read status: " + status);
- if (listener != null) {
- try {
- listener.onProgress(status);
- } catch (RemoteException unused) {
- Slog.w(TAG, "RemoteException when posting progress");
- }
+ if (status >= 0 && status <= 100) {
+ // Update status
+ Slog.i(TAG, "uncrypt read status: " + status);
+ if (listener != null) {
+ try {
+ listener.onProgress(status);
+ } catch (RemoteException unused) {
+ Slog.w(TAG, "RemoteException when posting progress");
}
- if (status == 100) {
- Slog.i(TAG, "uncrypt successfully finished.");
- break;
- }
- } else {
- // Error in /system/bin/uncrypt.
- Slog.e(TAG, "uncrypt failed with status: " + status);
- return false;
}
- } catch (NumberFormatException unused) {
- Slog.e(TAG, "uncrypt invalid status received: " + str);
+ if (status == 100) {
+ Slog.i(TAG, "uncrypt successfully finished.");
+ // Ack receipt of the final status code. uncrypt
+ // waits for the ack so the socket won't be
+ // destroyed before we receive the code.
+ dos.writeInt(0);
+ dos.flush();
+ break;
+ }
+ } else {
+ // Error in /system/bin/uncrypt.
+ Slog.e(TAG, "uncrypt failed with status: " + status);
+ // Ack receipt of the final status code. uncrypt waits
+ // for the ack so the socket won't be destroyed before
+ // we receive the code.
+ dos.writeInt(0);
+ dos.flush();
return false;
}
}
- } catch (IOException unused) {
- Slog.e(TAG, "IOException when reading \"" + UNCRYPT_STATUS_FILE + "\".");
+ } catch (IOException e) {
+ Slog.e(TAG, "IOException when reading status: " + e);
return false;
+ } finally {
+ IoUtils.closeQuietly(socket);
}
return true;
@@ -150,29 +157,35 @@
return setupOrClearBcb(true, command);
}
- private boolean setupOrClearBcb(boolean isSetup, String command) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
-
- if (isSetup) {
- // Set up the command file to be read by uncrypt.
- try (FileWriter commandFile = new FileWriter(COMMAND_FILE)) {
- commandFile.write(command + "\n");
- } catch (IOException e) {
- Slog.e(TAG, "IOException when writing \"" + COMMAND_FILE +
- "\": " + e.getMessage());
- return false;
+ private LocalSocket connectService() {
+ LocalSocket socket = new LocalSocket();
+ boolean done = false;
+ // The uncrypt socket will be created by init upon receiving the
+ // service request. It may not be ready by this point. So we will
+ // keep retrying until success or reaching timeout.
+ for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
+ try {
+ socket.connect(new LocalSocketAddress(UNCRYPT_SOCKET,
+ LocalSocketAddress.Namespace.RESERVED));
+ done = true;
+ break;
+ } catch (IOException unused) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ Slog.w(TAG, "Interrupted: " + e);
+ }
}
}
-
- // Create the status pipe file to communicate with uncrypt.
- new File(UNCRYPT_STATUS_FILE).delete();
- try {
- Os.mkfifo(UNCRYPT_STATUS_FILE, 0600);
- } catch (ErrnoException e) {
- Slog.e(TAG, "ErrnoException when creating named pipe \"" +
- UNCRYPT_STATUS_FILE + "\": " + e.getMessage());
- return false;
+ if (!done) {
+ Slog.e(TAG, "Timed out connecting to uncrypt socket");
+ return null;
}
+ return socket;
+ }
+
+ private boolean setupOrClearBcb(boolean isSetup, String command) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
if (isSetup) {
SystemProperties.set("ctl.start", "setup-bcb");
@@ -180,34 +193,45 @@
SystemProperties.set("ctl.start", "clear-bcb");
}
- // Read the status from the pipe.
- try (BufferedReader reader = new BufferedReader(new FileReader(UNCRYPT_STATUS_FILE))) {
- while (true) {
- String str = reader.readLine();
- try {
- int status = Integer.parseInt(str);
-
- if (status == 100) {
- Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") +
- " bcb successfully finished.");
- break;
- } else {
- // Error in /system/bin/uncrypt.
- Slog.e(TAG, "uncrypt failed with status: " + status);
- return false;
- }
- } catch (NumberFormatException unused) {
- Slog.e(TAG, "uncrypt invalid status received: " + str);
- return false;
- }
- }
- } catch (IOException unused) {
- Slog.e(TAG, "IOException when reading \"" + UNCRYPT_STATUS_FILE + "\".");
+ // Connect to the uncrypt service socket.
+ LocalSocket socket = connectService();
+ if (socket == null) {
+ Slog.e(TAG, "Failed to connect to uncrypt socket");
return false;
}
- // Delete the command file as we don't need it anymore.
- new File(COMMAND_FILE).delete();
+ try (DataInputStream dis = new DataInputStream(socket.getInputStream());
+ DataOutputStream dos = new DataOutputStream(socket.getOutputStream())) {
+ // Send the BCB commands if it's to setup BCB.
+ if (isSetup) {
+ dos.writeInt(command.length());
+ dos.writeBytes(command);
+ dos.flush();
+ }
+
+ // Read the status from the socket.
+ int status = dis.readInt();
+
+ // Ack receipt of the status code. uncrypt waits for the ack so
+ // the socket won't be destroyed before we receive the code.
+ dos.writeInt(0);
+ dos.flush();
+
+ if (status == 100) {
+ Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") +
+ " bcb successfully finished.");
+ } else {
+ // Error in /system/bin/uncrypt.
+ Slog.e(TAG, "uncrypt failed with status: " + status);
+ return false;
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "IOException when getting output stream: " + e);
+ return false;
+ } finally {
+ IoUtils.closeQuietly(socket);
+ }
+
return true;
}
}
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index 1c1784e..73d8bdd 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -105,9 +105,6 @@
// background while in data-usage save mode, as read from the configuration files.
final ArraySet<String> mAllowInDataUsageSave = new ArraySet<>();
- // These are the app package names that should not allow IME switching.
- final ArraySet<String> mFixedImeApps = new ArraySet<>();
-
// These are the package names of apps which should be in the 'always'
// URL-handling state upon factory reset.
final ArraySet<String> mLinkedApps = new ArraySet<>();
@@ -159,10 +156,6 @@
return mAllowInDataUsageSave;
}
- public ArraySet<String> getFixedImeApps() {
- return mFixedImeApps;
- }
-
public ArraySet<String> getLinkedApps() {
return mLinkedApps;
}
@@ -411,17 +404,6 @@
XmlUtils.skipCurrentTag(parser);
continue;
- } else if ("fixed-ime-app".equals(name) && allowAll) {
- String pkgname = parser.getAttributeValue(null, "package");
- if (pkgname == null) {
- Slog.w(TAG, "<fixed-ime-app> without package in " + permFile + " at "
- + parser.getPositionDescription());
- } else {
- mFixedImeApps.add(pkgname);
- }
- XmlUtils.skipCurrentTag(parser);
- continue;
-
} else if ("app-link".equals(name) && allowAppConfigs) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 8c0ec78..63a0e87 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -319,7 +319,7 @@
+ " (pid=" + Binder.getCallingPid()
+ ") when starting service " + service);
}
- callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
} else {
callerFg = true;
}
@@ -831,7 +831,7 @@
"BIND_TREAT_LIKE_ACTIVITY");
}
- final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
ServiceLookupResult res =
@@ -1138,7 +1138,7 @@
for (int i=b.apps.size()-1; i>=0; i--) {
ProcessRecord client = b.apps.valueAt(i).client;
if (client != null && client.setSchedGroup
- != Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+ != ProcessList.SCHED_GROUP_BACKGROUND) {
inFg = true;
break;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 4f0d4d9..f2bf4f9 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -46,6 +46,7 @@
// Available log categories in the activity manager package.
static final boolean DEBUG_ADD_REMOVE = DEBUG_ALL_ACTIVITIES || false;
+ static final boolean DEBUG_ANR = false;
static final boolean DEBUG_APP = DEBUG_ALL_ACTIVITIES || false;
static final boolean DEBUG_BACKUP = DEBUG_ALL || false;
static final boolean DEBUG_BROADCAST = DEBUG_ALL || false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7f297a8..037ec59 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -101,6 +101,8 @@
import android.app.PendingIntent;
import android.app.ProfilerInfo;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
+import android.app.admin.IDevicePolicyManager;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.backup.IBackupManager;
@@ -284,6 +286,7 @@
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_BACKGROUND;
@@ -1294,6 +1297,7 @@
boolean mAlwaysFinishActivities = false;
boolean mLenientBackgroundCheck = false;
boolean mForceResizableActivities;
+ boolean mSupportsMultiWindow;
boolean mSupportsFreeformWindowManagement;
boolean mSupportsPictureInPicture;
Rect mDefaultPinnedStackBounds;
@@ -5090,8 +5094,13 @@
int num = firstPids.size();
for (int i = 0; i < num; i++) {
synchronized (observer) {
+ if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for pid "
+ + firstPids.get(i));
+ final long sime = SystemClock.elapsedRealtime();
Process.sendSignal(firstPids.get(i), Process.SIGNAL_QUIT);
- observer.wait(200); // Wait for write-close, give up after 200msec
+ observer.wait(1000); // Wait for write-close, give up after 1 sec
+ if (DEBUG_ANR) Slog.d(TAG, "Done with pid " + firstPids.get(i)
+ + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
}
}
} catch (InterruptedException e) {
@@ -5104,7 +5113,11 @@
int[] pids = Process.getPidsForCommands(nativeProcs);
if (pids != null) {
for (int pid : pids) {
+ if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native pid " + pid);
+ final long sime = SystemClock.elapsedRealtime();
Debug.dumpNativeBacktraceToFile(pid, tracesPath);
+ if (DEBUG_ANR) Slog.d(TAG, "Done with native pid " + pid
+ + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
}
}
}
@@ -5131,13 +5144,20 @@
numProcs++;
try {
synchronized (observer) {
+ if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid "
+ + stats.pid);
+ final long stime = SystemClock.elapsedRealtime();
Process.sendSignal(stats.pid, Process.SIGNAL_QUIT);
- observer.wait(200); // Wait for write-close, give up after 200msec
+ observer.wait(1000); // Wait for write-close, give up after 1 sec
+ if (DEBUG_ANR) Slog.d(TAG, "Done with extra pid " + stats.pid
+ + " in " + (SystemClock.elapsedRealtime()-stime) + "ms");
}
} catch (InterruptedException e) {
Slog.wtf(TAG, e);
}
-
+ } else if (DEBUG_ANR) {
+ Slog.d(TAG, "Skipping next CPU consuming process, not a java proc: "
+ + stats.pid);
}
}
}
@@ -5243,9 +5263,13 @@
public boolean clearApplicationUserData(final String packageName,
final IPackageDataObserver observer, int userId) {
enforceNotIsolatedCaller("clearApplicationUserData");
- if (packageName != null && packageName.equals(mDeviceOwnerName)) {
- throw new SecurityException("Clearing DeviceOwner data is forbidden.");
+
+ final DevicePolicyManagerInternal dpmi = LocalServices
+ .getService(DevicePolicyManagerInternal.class);
+ if (dpmi != null && dpmi.hasDeviceOwnerOrProfileOwner(packageName, userId)) {
+ throw new SecurityException("Cannot clear data for a device owner or a profile owner");
}
+
int uid = Binder.getCallingUid();
int pid = Binder.getCallingPid();
userId = mUserController.handleIncomingUser(pid, uid, userId, false,
@@ -6211,7 +6235,7 @@
app.makeActive(thread, mProcessStats);
app.curAdj = app.setAdj = ProcessList.INVALID_ADJ;
- app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
+ app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.forcingToForeground = null;
updateProcessForegroundLocked(app, false, false);
app.hasShownUi = false;
@@ -6269,9 +6293,10 @@
// If the app is being launched for restore or full backup, set it up specially
boolean isRestrictedBackupMode = false;
if (mBackupTarget != null && mBackupAppName.equals(processName)) {
- isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
- || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
- || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
+ isRestrictedBackupMode = mBackupTarget.appInfo.uid >= Process.FIRST_APPLICATION_UID
+ && ((mBackupTarget.backupMode == BackupRecord.RESTORE)
+ || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
+ || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
}
notifyPackageUse(app.instrumentationInfo != null
@@ -9202,7 +9227,7 @@
// Kill the running processes.
for (int i = 0; i < procsToKill.size(); i++) {
ProcessRecord pr = procsToKill.get(i);
- if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
&& pr.curReceiver == null) {
pr.kill("remove task", true);
} else {
@@ -9616,6 +9641,20 @@
}
@Override
+ public void resizePinnedStack(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
+ enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+ "resizePinnedStack()");
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ mStackSupervisor.resizePinnedStackLocked(pinnedBounds, tempPinnedTaskBounds);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
public void positionTaskInStack(int taskId, int stackId, int position) {
enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "positionTaskInStack()");
if (stackId == HOME_STACK_ID) {
@@ -10463,7 +10502,7 @@
cpi.packageName, r.userId)) {
final boolean callerForeground = r != null ? r.setSchedGroup
- != Process.THREAD_GROUP_BG_NONINTERACTIVE : true;
+ != ProcessList.SCHED_GROUP_BACKGROUND : true;
// Show a permission review UI only for starting from a foreground app
if (!callerForeground) {
@@ -10783,12 +10822,13 @@
return;
}
- final long token = Binder.clearCallingIdentity();
- try {
- mAppErrors.appNotResponding(host, null, null, false, "ContentProvider not responding");
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mAppErrors.appNotResponding(host, null, null, false,
+ "ContentProvider not responding");
+ }
+ });
}
public final void installSystemProviders() {
@@ -12371,6 +12411,7 @@
final boolean supportsPictureInPicture =
mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
+ final boolean supportsMultiWindow = ActivityManager.supportsMultiWindow();
final String debugApp = Settings.Global.getString(resolver, DEBUG_APP);
final boolean waitForDebugger = Settings.Global.getInt(resolver, WAIT_FOR_DEBUGGER, 0) != 0;
final boolean alwaysFinishActivities =
@@ -12397,8 +12438,15 @@
mLenientBackgroundCheck = lenientBackgroundCheck;
mForceResizableActivities = forceResizable;
mWindowManager.setForceResizableTasks(mForceResizableActivities);
- mSupportsFreeformWindowManagement = freeformWindowManagement || forceResizable;
- mSupportsPictureInPicture = supportsPictureInPicture || forceResizable;
+ if (supportsMultiWindow || forceResizable) {
+ mSupportsMultiWindow = true;
+ mSupportsFreeformWindowManagement = freeformWindowManagement || forceResizable;
+ mSupportsPictureInPicture = supportsPictureInPicture || forceResizable;
+ } else {
+ mSupportsMultiWindow = false;
+ mSupportsFreeformWindowManagement = false;
+ mSupportsPictureInPicture = false;
+ }
// This happens before any activities are started, so we can
// change mConfiguration in-place.
updateConfigurationLocked(configuration, null, true);
@@ -14771,13 +14819,13 @@
String oomAdj = ProcessList.makeOomAdjString(r.setAdj);
char schedGroup;
switch (r.setSchedGroup) {
- case Process.THREAD_GROUP_BG_NONINTERACTIVE:
+ case ProcessList.SCHED_GROUP_BACKGROUND:
schedGroup = 'B';
break;
- case Process.THREAD_GROUP_DEFAULT:
+ case ProcessList.SCHED_GROUP_DEFAULT:
schedGroup = 'F';
break;
- case Process.THREAD_GROUP_TOP_APP:
+ case ProcessList.SCHED_GROUP_TOP_APP:
schedGroup = 'T';
break;
default:
@@ -17185,10 +17233,11 @@
String ssp;
if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);
- boolean fullUninstall = removed &&
- !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+ final boolean replacing =
+ intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
final boolean killProcess =
!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false);
+ final boolean fullUninstall = removed && !replacing;
if (killProcess) {
forceStopPackageLocked(ssp, UserHandle.getAppId(
intent.getIntExtra(Intent.EXTRA_UID, -1)),
@@ -17196,7 +17245,10 @@
removed ? "pkg removed" : "pkg changed");
}
if (removed) {
- sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
+ final int cmd = killProcess
+ ? IApplicationThread.PACKAGE_REMOVED
+ : IApplicationThread.PACKAGE_REMOVED_DONT_KILL;
+ sendPackageBroadcastLocked(cmd,
new String[] {ssp}, userId);
if (fullUninstall) {
mAppOpsService.packageRemoved(
@@ -17231,7 +17283,23 @@
break;
}
break;
+ case Intent.ACTION_PACKAGE_REPLACED:
+ {
+ final Uri data = intent.getData();
+ final String ssp;
+ if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
+ final ApplicationInfo aInfo =
+ getPackageManagerInternalLocked().getApplicationInfo(
+ ssp,
+ userId);
+ mStackSupervisor.updateActivityApplicationInfoLocked(aInfo);
+ sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REPLACED,
+ new String[] {ssp}, userId);
+ }
+ break;
+ }
case Intent.ACTION_PACKAGE_ADDED:
+ {
// Special case for adding a package: by default turn on compatibility mode.
Uri data = intent.getData();
String ssp;
@@ -17249,6 +17317,7 @@
}
}
break;
+ }
case Intent.ACTION_TIMEZONE_CHANGED:
// If this is the time zone changed action, queue up a message that will reset
// the timezone of all currently running processes. This message will get
@@ -18312,7 +18381,7 @@
if (app.thread == null) {
app.adjSeq = mAdjSeq;
- app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ app.curSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);
}
@@ -18332,7 +18401,7 @@
app.adjSeq = mAdjSeq;
app.curRawAdj = app.maxAdj;
app.foregroundActivities = false;
- app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
+ app.curSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;
// System processes can do UI, and when they do we want to have
// them trim their memory after the user leaves the UI. To
@@ -18369,14 +18438,14 @@
if (app == TOP_APP) {
// The last app on the list is the foreground app.
adj = ProcessList.FOREGROUND_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_TOP_APP;
+ schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
app.adjType = "top-activity";
foregroundActivities = true;
procState = PROCESS_STATE_CUR_TOP;
} else if (app.instrumentationClass != null) {
// Don't want to kill running instrumentation.
adj = ProcessList.FOREGROUND_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.adjType = "instrumentation";
procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
} else if ((queue = isReceivingBroadcast(app)) != null) {
@@ -18386,7 +18455,7 @@
// broadcast as reflected by which queue it's active in.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = (queue == mFgBroadcastQueue)
- ? Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
app.adjType = "broadcast";
procState = ActivityManager.PROCESS_STATE_RECEIVER;
} else if (app.executingServices.size() > 0) {
@@ -18394,13 +18463,13 @@
// counts as being in the foreground.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = app.execServicesFg ?
- Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
app.adjType = "exec-service";
procState = ActivityManager.PROCESS_STATE_SERVICE;
//Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);
} else {
// As far as we know the process is empty. We may change our mind later.
- schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
// At this point we don't actually know the adjustment. Use the cached adj
// value that the caller wants us to.
adj = cachedAdj;
@@ -18429,7 +18498,7 @@
if (procState > PROCESS_STATE_CUR_TOP) {
procState = PROCESS_STATE_CUR_TOP;
}
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.cached = false;
app.empty = false;
foregroundActivities = true;
@@ -18448,7 +18517,7 @@
if (procState > PROCESS_STATE_CUR_TOP) {
procState = PROCESS_STATE_CUR_TOP;
}
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.cached = false;
app.empty = false;
foregroundActivities = true;
@@ -18492,7 +18561,7 @@
procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
app.cached = false;
app.adjType = "fg-service";
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
} else if (app.forcingToForeground != null) {
// The user is aware of this app, so make it visible.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
@@ -18500,7 +18569,7 @@
app.cached = false;
app.adjType = "force-fg";
app.adjSource = app.forcingToForeground;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
}
@@ -18508,7 +18577,7 @@
if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
// We don't want to kill the current heavy-weight process.
adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.cached = false;
app.adjType = "heavy";
}
@@ -18522,7 +18591,7 @@
// This process is hosting what we currently consider to be the
// home app, so we don't want to let it go into the background.
adj = ProcessList.HOME_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.cached = false;
app.adjType = "home";
}
@@ -18537,7 +18606,7 @@
// We want to try to keep it around more aggressively, to give
// a good experience around switching between two apps.
adj = ProcessList.PREVIOUS_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.cached = false;
app.adjType = "previous";
}
@@ -18577,7 +18646,7 @@
for (int is = app.services.size()-1;
is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > ActivityManager.PROCESS_STATE_TOP);
is--) {
ServiceRecord s = app.services.valueAt(is);
@@ -18615,13 +18684,13 @@
}
for (int conni = s.connections.size()-1;
conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > ActivityManager.PROCESS_STATE_TOP);
conni--) {
ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
for (int i = 0;
i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > ActivityManager.PROCESS_STATE_TOP);
i++) {
// XXX should compute this based on the max of
@@ -18713,7 +18782,7 @@
if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
schedGroup = client.curSchedGroup;
} else {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
}
if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
@@ -18783,9 +18852,9 @@
adj = ProcessList.FOREGROUND_APP_ADJ;
if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
- schedGroup = Process.THREAD_GROUP_TOP_APP;
+ schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
} else {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
}
app.cached = false;
@@ -18803,13 +18872,13 @@
for (int provi = app.pubProviders.size()-1;
provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > ActivityManager.PROCESS_STATE_TOP);
provi--) {
ContentProviderRecord cpr = app.pubProviders.valueAt(provi);
for (int i = cpr.connections.size()-1;
i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > ActivityManager.PROCESS_STATE_TOP);
i--) {
ContentProviderConnection conn = cpr.connections.get(i);
@@ -18867,7 +18936,7 @@
procState = clientProcState;
}
if (client.curSchedGroup > schedGroup) {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
}
// If the provider has external (non-framework) process
@@ -18876,7 +18945,7 @@
if (cpr.hasExternalProcessHandles()) {
if (adj > ProcessList.FOREGROUND_APP_ADJ) {
adj = ProcessList.FOREGROUND_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.cached = false;
app.adjType = "provider";
app.adjTarget = cpr.name;
@@ -18890,7 +18959,7 @@
if (app.lastProviderTime > 0 && (app.lastProviderTime+CONTENT_PROVIDER_RETAIN_TIME) > now) {
if (adj > ProcessList.PREVIOUS_APP_ADJ) {
adj = ProcessList.PREVIOUS_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.cached = false;
app.adjType = "provider";
}
@@ -18969,7 +19038,7 @@
if (adj > app.maxAdj) {
adj = app.maxAdj;
if (app.maxAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
}
@@ -19385,17 +19454,29 @@
if (app.setSchedGroup != app.curSchedGroup) {
app.setSchedGroup = app.curSchedGroup;
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
- "Setting process group of " + app.processName
+ "Setting sched group of " + app.processName
+ " to " + app.curSchedGroup);
if (app.waitingToKill != null && app.curReceiver == null
- && app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+ && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
app.kill(app.waitingToKill, true);
success = false;
} else {
+ int processGroup;
+ switch (app.curSchedGroup) {
+ case ProcessList.SCHED_GROUP_BACKGROUND:
+ processGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ break;
+ case ProcessList.SCHED_GROUP_TOP_APP:
+ processGroup = Process.THREAD_GROUP_TOP_APP;
+ break;
+ default:
+ processGroup = Process.THREAD_GROUP_DEFAULT;
+ break;
+ }
if (true) {
long oldId = Binder.clearCallingIdentity();
try {
- Process.setProcessGroup(app.pid, app.curSchedGroup);
+ Process.setProcessGroup(app.pid, processGroup);
} catch (Exception e) {
Slog.w(TAG, "Failed setting process group of " + app.pid
+ " to " + app.curSchedGroup);
@@ -19406,7 +19487,7 @@
} else {
if (app.thread != null) {
try {
- app.thread.setSchedulingGroup(app.curSchedGroup);
+ app.thread.setSchedulingGroup(processGroup);
} catch (RemoteException e) {
}
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index d5e40cf..e430dad 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -76,6 +76,7 @@
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
@@ -252,6 +253,10 @@
pw.print(prefix); pw.print("resDir="); pw.println(appInfo.publicSourceDir);
}
pw.print(prefix); pw.print("dataDir="); pw.println(appInfo.dataDir);
+ if (appInfo.splitSourceDirs != null) {
+ pw.print(prefix); pw.print("splitDir=");
+ pw.println(Arrays.toString(appInfo.splitSourceDirs));
+ }
}
pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded);
pw.print(" componentSpecified="); pw.print(componentSpecified);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 769bee4..d1e1d27 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -65,6 +65,8 @@
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Uri;
@@ -184,7 +186,7 @@
* The back history of all previous (and possibly still
* running) activities. It contains #TaskRecord objects.
*/
- private ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
+ private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
/**
* Used for validating app tokens with window manager.
@@ -839,6 +841,18 @@
}
}
+ void updateActivityApplicationInfoLocked(ApplicationInfo aInfo) {
+ final String packageName = aInfo.packageName;
+ for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+ final List<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+ for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+ if (packageName.equals(activities.get(activityNdx).packageName)) {
+ activities.get(activityNdx).info.applicationInfo = aInfo;
+ }
+ }
+ }
+ }
+
/**
* @return true if something must be done before going to sleep.
*/
@@ -1101,7 +1115,7 @@
r.stopped = true;
r.state = ActivityState.STOPPED;
- mWindowManager.notifyAppStopped(r.appToken);
+ mWindowManager.notifyAppStopped(r.appToken, true);
if (getVisibleBehindActivity() == r) {
mStackSupervisor.requestVisibleBehindLocked(r, false);
@@ -2233,6 +2247,10 @@
next.app.thread.scheduleNewIntent(next.newIntents, next.appToken);
}
+ // Well the app will no longer be stopped.
+ // Clear app token stopped state in window manager if needed.
+ mWindowManager.notifyAppStopped(next.appToken, false);
+
EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
System.identityHashCode(next), next.task.taskId, next.shortComponentName);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c6813604..48f31f9 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1700,6 +1700,15 @@
return false;
}
+ void updateActivityApplicationInfoLocked(ApplicationInfo aInfo) {
+ for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+ final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+ for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ stacks.get(stackNdx).updateActivityApplicationInfoLocked(aInfo);
+ }
+ }
+ }
+
TaskRecord finishTopRunningActivityLocked(ProcessRecord app, String reason) {
TaskRecord finishedTask = null;
ActivityStack focusedStack = getFocusedStack();
@@ -2034,6 +2043,25 @@
|| tempOtherTaskInsetBounds != null);
}
+ void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
+ final ActivityStack stack = getStack(PINNED_STACK_ID);
+ if (stack == null) {
+ Slog.w(TAG, "resizePinnedStackLocked: pinned stack not found");
+ return;
+ }
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizePinnedStack");
+ mWindowManager.deferSurfaceLayout();
+ try {
+ ActivityRecord r = stack.topRunningActivityLocked();
+ resizeStackUncheckedLocked(stack, pinnedBounds, tempPinnedTaskBounds,
+ null);
+ ensureConfigurationAndResume(stack, r, false);
+ } finally {
+ mWindowManager.continueSurfaceLayout();
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ }
+ }
+
boolean resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) {
if (!task.isResizeable()) {
Slog.w(TAG, "resizeTask: task " + task + " not resizeable.");
@@ -2174,6 +2202,12 @@
*/
ActivityStack moveTaskToStackUncheckedLocked(
TaskRecord task, int stackId, boolean toTop, boolean forceFocus, String reason) {
+
+ if (StackId.isMultiWindowStack(stackId) && !mService.mSupportsMultiWindow) {
+ throw new IllegalStateException("moveTaskToStackUncheckedLocked: Device doesn't "
+ + "support multi-window task=" + task + " to stackId=" + stackId);
+ }
+
final ActivityRecord r = task.getTopActivity();
final ActivityStack prevStack = task.stack;
final boolean wasFocused = isFocusedStack(prevStack) && (topRunningActivityLocked() == r);
@@ -2184,8 +2218,6 @@
final boolean wasFront = isFrontStack(prevStack)
&& (prevStack.topRunningActivityLocked() == r);
- final int resizeMode = task.mResizeMode;
-
if (stackId == DOCKED_STACK_ID && !task.isResizeable()) {
// We don't allow moving a unresizeable task to the docked stack since the docked
// stack is used for split-screen mode and will cause things like the docked divider to
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index bcdc800..46389e2 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1772,12 +1772,13 @@
return false;
}
- if (stackId == DOCKED_STACK_ID && r.canGoInDockedStack()) {
- return true;
+ if (stackId != FULLSCREEN_WORKSPACE_STACK_ID
+ && (!mService.mSupportsMultiWindow || !r.isResizeableOrForced())) {
+ return false;
}
- if (stackId != FULLSCREEN_WORKSPACE_STACK_ID && !r.isResizeableOrForced()) {
- return false;
+ if (stackId == DOCKED_STACK_ID && r.canGoInDockedStack()) {
+ return true;
}
if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) {
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 055935d..6cd7561 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -61,6 +61,7 @@
import java.util.concurrent.Semaphore;
import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.MY_PID;
@@ -806,8 +807,10 @@
if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
if (r.persistent) {
firstPids.add(pid);
+ if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);
} else {
lastPids.put(pid, Boolean.TRUE);
+ if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r);
}
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 37b0af1..45e3a76 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -654,7 +654,7 @@
}
final boolean callerForeground = receiverRecord.callerApp != null
- ? receiverRecord.callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE
+ ? receiverRecord.callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND
: true;
// Show a permission review UI only for explicit broadcast from a foreground app
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index b49370b..f073e5c 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -124,6 +124,13 @@
// Memory pages are 4K.
static final int PAGE_SIZE = 4*1024;
+ // Activity manager's version of Process.THREAD_GROUP_BG_NONINTERACTIVE
+ static final int SCHED_GROUP_BACKGROUND = 0;
+ // Activity manager's version of Process.THREAD_GROUP_DEFAULT
+ static final int SCHED_GROUP_DEFAULT = 1;
+ // Activity manager's version of Process.THREAD_GROUP_TOP_APP
+ static final int SCHED_GROUP_TOP_APP = 2;
+
// The minimum number of cached apps we want to be able to keep around,
// without empty apps being able to push them out of memory.
static final int MIN_CACHED_APPS = 2;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 5a3639a..f2a9c2c 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -849,7 +849,7 @@
AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
mDockAudioMediaEnabled ?
AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
- readEncodedSurroundMode(mContentResolver);
+ sendEncodedSurroundMode(mContentResolver);
}
if (mHdmiManager != null) {
synchronized (mHdmiManager) {
@@ -1023,7 +1023,7 @@
AudioSystem.setMasterMono(masterMono);
}
- private void readEncodedSurroundMode(ContentResolver cr)
+ private void sendEncodedSurroundMode(ContentResolver cr)
{
int encodedSurroundMode = Settings.Global.getInt(
cr, Settings.Global.ENCODED_SURROUND_OUTPUT,
@@ -1102,7 +1102,7 @@
updateRingerModeAffectedStreams();
readDockAudioSettings(cr);
- readEncodedSurroundMode(cr);
+ sendEncodedSurroundMode(cr);
}
mMuteAffectedStreams = System.getIntForUser(cr,
@@ -4642,6 +4642,8 @@
private class SettingsObserver extends ContentObserver {
+ private int mEncodedSurroundMode;
+
SettingsObserver() {
super(new Handler());
mContentResolver.registerContentObserver(Settings.System.getUriFor(
@@ -4650,6 +4652,12 @@
Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
mContentResolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.MASTER_MONO), false, this);
+
+ mEncodedSurroundMode = Settings.Global.getInt(
+ mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
+ Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
+ mContentResolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.ENCODED_SURROUND_OUTPUT), false, this);
}
@Override
@@ -4669,7 +4677,33 @@
}
readDockAudioSettings(mContentResolver);
updateMasterMono(mContentResolver);
- readEncodedSurroundMode(mContentResolver);
+ updateEncodedSurroundOutput();
+ }
+ }
+
+ private void updateEncodedSurroundOutput() {
+ int newSurroundMode = Settings.Global.getInt(
+ mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
+ Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
+ // Did it change?
+ if (mEncodedSurroundMode != newSurroundMode) {
+ // Send to AudioPolicyManager
+ sendEncodedSurroundMode(newSurroundMode);
+ synchronized(mConnectedDevices) {
+ // Is HDMI connected?
+ String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_HDMI, "");
+ DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+ if (deviceSpec != null) {
+ // Toggle HDMI to retrigger broadcast with proper formats.
+ setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE, "", "",
+ "android"); // disconnect
+ setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
+ AudioSystem.DEVICE_STATE_AVAILABLE, "", "",
+ "android"); // reconnect
+ }
+ }
+ mEncodedSurroundMode = newSurroundMode;
}
}
}
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
index 7e76ac4..86dcd0f 100644
--- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -54,12 +54,15 @@
if (MediaRecorder.isSystemOnlyAudioSource(source)) {
return;
}
- if (updateSnapshot(event, session, source, recordingInfo)) {
- final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
+ final AudioRecordConfiguration[] configs =
+ updateSnapshot(event, session, source, recordingInfo);
+ if (configs != null){
synchronized(mClients) {
+ final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
while (clientIterator.hasNext()) {
try {
- clientIterator.next().mDispatcherCb.dispatchRecordingConfigChange();
+ clientIterator.next().mDispatcherCb.dispatchRecordingConfigChange(
+ configs);
} catch (RemoteException e) {
Log.w(TAG, "Could not call dispatchRecordingConfigChange() on client", e);
}
@@ -115,14 +118,19 @@
* @param recordingFormat see
* {@link AudioSystem.AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int[])}
* for the definition of the contents of the array
- * @return true if the list of active recording sessions has been modified, false otherwise.
+ * @return null if the list of active recording sessions has not been modified, an array
+ * with the current active configurations otherwise.
*/
- private boolean updateSnapshot(int event, int session, int source, int[] recordingInfo) {
+ private AudioRecordConfiguration[] updateSnapshot(int event, int session, int source,
+ int[] recordingInfo) {
+ final boolean configChanged;
+ final AudioRecordConfiguration[] configs;
synchronized(mRecordConfigs) {
switch (event) {
case AudioManager.RECORD_CONFIG_EVENT_STOP:
// return failure if an unknown recording session stopped
- return (mRecordConfigs.remove(new Integer(session)) != null);
+ configChanged = (mRecordConfigs.remove(new Integer(session)) != null);
+ break;
case AudioManager.RECORD_CONFIG_EVENT_START:
final AudioFormat clientFormat = new AudioFormat.Builder()
.setEncoding(recordingInfo[0])
@@ -143,25 +151,32 @@
new AudioRecordConfiguration(session, source,
clientFormat, deviceFormat, patchHandle);
if (updatedConfig.equals(mRecordConfigs.get(sessionKey))) {
- return false;
+ configChanged = false;
} else {
// config exists but has been modified
mRecordConfigs.remove(sessionKey);
mRecordConfigs.put(sessionKey, updatedConfig);
- return true;
+ configChanged = true;
}
} else {
mRecordConfigs.put(sessionKey,
new AudioRecordConfiguration(session, source,
clientFormat, deviceFormat, patchHandle));
- return true;
+ configChanged = true;
}
+ break;
default:
Log.e(TAG, String.format("Unknown event %d for session %d, source %d",
event, session, source));
- return false;
+ configChanged = false;
+ }
+ if (configChanged) {
+ configs = mRecordConfigs.values().toArray(new AudioRecordConfiguration[0]);
+ } else {
+ configs = null;
}
}
+ return configs;
}
/**
diff --git a/services/core/java/com/android/server/camera/CameraService.java b/services/core/java/com/android/server/camera/CameraService.java
index f82454a..cd8eb4e 100644
--- a/services/core/java/com/android/server/camera/CameraService.java
+++ b/services/core/java/com/android/server/camera/CameraService.java
@@ -60,10 +60,6 @@
public static final String CAMERA_SERVICE_PROXY_BINDER_NAME = "media.camera.proxy";
- // Event arguments to use with the camera service notifySystemEvent call:
- public static final int NO_EVENT = 0; // NOOP
- public static final int USER_SWITCHED = 1; // User changed, argument is the new user handle
-
// State arguments to use with the notifyCameraState call from camera service:
public static final int CAMERA_STATE_OPEN = 0;
public static final int CAMERA_STATE_ACTIVE = 1;
@@ -224,7 +220,7 @@
if (mEnabledCameraUsers == null || !mEnabledCameraUsers.equals(currentUserHandles)) {
// Some user handles have been added or removed, update mediaserver.
mEnabledCameraUsers = currentUserHandles;
- notifyMediaserverLocked(USER_SWITCHED, currentUserHandles);
+ notifyMediaserverLocked(ICameraService.EVENT_USER_SWITCHED, currentUserHandles);
}
}
@@ -244,7 +240,7 @@
if (mEnabledCameraUsers == null) {
return;
}
- if (notifyMediaserverLocked(USER_SWITCHED, mEnabledCameraUsers)) {
+ if (notifyMediaserverLocked(ICameraService.EVENT_USER_SWITCHED, mEnabledCameraUsers)) {
retries = 0;
}
}
diff --git a/services/core/java/com/android/server/connectivity/ApfFilter.java b/services/core/java/com/android/server/connectivity/ApfFilter.java
new file mode 100644
index 0000000..25c84e1
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/ApfFilter.java
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2016 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.connectivity;
+
+import static android.system.OsConstants.*;
+
+import android.net.NetworkUtils;
+import android.net.apf.ApfGenerator;
+import android.net.apf.ApfGenerator.IllegalInstructionException;
+import android.net.apf.ApfGenerator.Register;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.PacketSocketAddress;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.util.HexDump;
+import com.android.server.ConnectivityService;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.lang.Thread;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import libcore.io.IoBridge;
+
+/**
+ * For networks that support packet filtering via APF programs, {@code ApfFilter}
+ * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to
+ * filter out redundant duplicate ones.
+ *
+ * @hide
+ */
+public class ApfFilter {
+ // Thread to listen for RAs.
+ private class ReceiveThread extends Thread {
+ private final byte[] mPacket = new byte[1514];
+ private final FileDescriptor mSocket;
+ private volatile boolean mStopped;
+
+ public ReceiveThread(FileDescriptor socket) {
+ mSocket = socket;
+ }
+
+ public void halt() {
+ mStopped = true;
+ try {
+ // Interrupts the read() call the thread is blocked in.
+ IoBridge.closeAndSignalBlockedThreads(mSocket);
+ } catch (IOException ignored) {}
+ }
+
+ @Override
+ public void run() {
+ log("begin monitoring");
+ while (!mStopped) {
+ try {
+ int length = Os.read(mSocket, mPacket, 0, mPacket.length);
+ processRa(mPacket, length);
+ } catch (IOException|ErrnoException e) {
+ if (!mStopped) {
+ Log.e(TAG, "Read error", e);
+ }
+ }
+ }
+ }
+ }
+
+ private static final String TAG = "ApfFilter";
+
+ private final ConnectivityService mConnectivityService;
+ private final NetworkAgentInfo mNai;
+ private ReceiveThread mReceiveThread;
+ private String mIfaceName;
+ private long mUniqueCounter;
+
+ private ApfFilter(ConnectivityService connectivityService, NetworkAgentInfo nai) {
+ mConnectivityService = connectivityService;
+ mNai = nai;
+ maybeStartFilter();
+ }
+
+ private void log(String s) {
+ Log.d(TAG, "(" + mNai.network.netId + "): " + s);
+ }
+
+ private long getUniqueNumber() {
+ return mUniqueCounter++;
+ }
+
+ /**
+ * Attempt to start listening for RAs and, if RAs are received, generating and installing
+ * filters to ignore useless RAs.
+ */
+ private void maybeStartFilter() {
+ mIfaceName = mNai.linkProperties.getInterfaceName();
+ if (mIfaceName == null) return;
+ FileDescriptor socket;
+ try {
+ socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6);
+ PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6,
+ NetworkInterface.getByName(mIfaceName).getIndex());
+ Os.bind(socket, addr);
+ NetworkUtils.attachRaFilter(socket, mNai.networkMisc.apfPacketFormat);
+ } catch(SocketException|ErrnoException e) {
+ Log.e(TAG, "Error filtering raw socket", e);
+ return;
+ }
+ mReceiveThread = new ReceiveThread(socket);
+ mReceiveThread.start();
+ }
+
+ /**
+ * mNai's LinkProperties may have changed, take appropriate action.
+ */
+ public void updateFilter() {
+ // If we're not listening for RAs, try starting.
+ if (mReceiveThread == null) {
+ maybeStartFilter();
+ // If interface name has changed, restart.
+ } else if (!mIfaceName.equals(mNai.linkProperties.getInterfaceName())) {
+ shutdown();
+ maybeStartFilter();
+ }
+ }
+
+ // Returns seconds since Unix Epoch.
+ private static long curTime() {
+ return System.currentTimeMillis() / 1000L;
+ }
+
+ // A class to hold information about an RA.
+ private class Ra {
+ private static final int ETH_HEADER_LEN = 14;
+
+ private static final int IPV6_HEADER_LEN = 40;
+
+ // From RFC4861:
+ private static final int ICMP6_RA_HEADER_LEN = 16;
+ private static final int ICMP6_RA_OPTION_OFFSET =
+ ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
+ private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
+ ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
+ private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2;
+ // Prefix information option.
+ private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
+ private static final int ICMP6_PREFIX_OPTION_LEN = 32;
+ private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
+ private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4;
+ private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
+ private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4;
+
+ // From RFC6106: Recursive DNS Server option
+ private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
+ // From RFC6106: DNS Search List option
+ private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
+
+ // From RFC4191: Route Information option
+ private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
+ // Above three options all have the same format:
+ private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
+ private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
+
+ private final ByteBuffer mPacket;
+ // List of binary ranges that include the whole packet except the lifetimes.
+ // Pairs consist of offset and length.
+ private final ArrayList<Pair<Integer, Integer>> mNonLifetimes =
+ new ArrayList<Pair<Integer, Integer>>();
+ // Minimum lifetime in packet
+ long mMinLifetime;
+ // When the packet was last captured, in seconds since Unix Epoch
+ long mLastSeen;
+
+ /**
+ * Add a binary range of the packet that does not include a lifetime to mNonLifetimes.
+ * Assumes mPacket.position() is as far as we've parsed the packet.
+ * @param lastNonLifetimeStart offset within packet of where the last binary range of
+ * data not including a lifetime.
+ * @param lifetimeOffset offset from mPacket.position() to the next lifetime data.
+ * @param lifetimeLength length of the next lifetime data.
+ * @return offset within packet of where the next binary range of data not including
+ * a lifetime. This can be passed into the next invocation of this function
+ * via {@code lastNonLifetimeStart}.
+ */
+ private int addNonLifetime(int lastNonLifetimeStart, int lifetimeOffset,
+ int lifetimeLength) {
+ lifetimeOffset += mPacket.position();
+ mNonLifetimes.add(new Pair<Integer, Integer>(lastNonLifetimeStart,
+ lifetimeOffset - lastNonLifetimeStart));
+ return lifetimeOffset + lifetimeLength;
+ }
+
+ // Note that this parses RA and may throw IllegalArgumentException (from
+ // Buffer.position(int) ) or IndexOutOfBoundsException (from ByteBuffer.get(int) ) if
+ // parsing encounters something non-compliant with specifications.
+ Ra(byte[] packet, int length) {
+ mPacket = ByteBuffer.allocate(length).put(ByteBuffer.wrap(packet, 0, length));
+ mPacket.clear();
+ mLastSeen = curTime();
+
+ // Parse router lifetime
+ int lastNonLifetimeStart = addNonLifetime(0, ICMP6_RA_ROUTER_LIFETIME_OFFSET,
+ ICMP6_RA_ROUTER_LIFETIME_LEN);
+ // Parse ICMP6 options
+ mPacket.position(ICMP6_RA_OPTION_OFFSET);
+ while (mPacket.hasRemaining()) {
+ int optionType = ((int)mPacket.get(mPacket.position())) & 0xff;
+ int optionLength = (((int)mPacket.get(mPacket.position() + 1)) & 0xff) * 8;
+ switch (optionType) {
+ case ICMP6_PREFIX_OPTION_TYPE:
+ // Parse valid lifetime
+ lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
+ ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
+ ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN);
+ // Parse preferred lifetime
+ lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
+ ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
+ ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN);
+ break;
+ // These three options have the same lifetime offset and size, so process
+ // together:
+ case ICMP6_ROUTE_INFO_OPTION_TYPE:
+ case ICMP6_RDNSS_OPTION_TYPE:
+ case ICMP6_DNSSL_OPTION_TYPE:
+ // Parse lifetime
+ lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
+ ICMP6_4_BYTE_LIFETIME_OFFSET,
+ ICMP6_4_BYTE_LIFETIME_LEN);
+ break;
+ default:
+ // RFC4861 section 4.2 dictates we ignore unknown options for fowards
+ // compatibility.
+ break;
+ }
+ mPacket.position(mPacket.position() + optionLength);
+ }
+ // Mark non-lifetime bytes since last lifetime.
+ addNonLifetime(lastNonLifetimeStart, 0, 0);
+ mMinLifetime = minLifetime(packet, length);
+ }
+
+ // Ignoring lifetimes (which may change) does {@code packet} match this RA?
+ boolean matches(byte[] packet, int length) {
+ if (length != mPacket.limit()) return false;
+ ByteBuffer a = ByteBuffer.wrap(packet);
+ ByteBuffer b = mPacket;
+ for (Pair<Integer, Integer> nonLifetime : mNonLifetimes) {
+ a.clear();
+ b.clear();
+ a.position(nonLifetime.first);
+ b.position(nonLifetime.first);
+ a.limit(nonLifetime.first + nonLifetime.second);
+ b.limit(nonLifetime.first + nonLifetime.second);
+ if (a.compareTo(b) != 0) return false;
+ }
+ return true;
+ }
+
+ // What is the minimum of all lifetimes within {@code packet} in seconds?
+ // Precondition: matches(packet, length) already returned true.
+ long minLifetime(byte[] packet, int length) {
+ long minLifetime = Long.MAX_VALUE;
+ // Wrap packet in ByteBuffer so we can read big-endian values easily
+ ByteBuffer byteBuffer = ByteBuffer.wrap(packet);
+ for (int i = 0; (i + 1) < mNonLifetimes.size(); i++) {
+ int offset = mNonLifetimes.get(i).first + mNonLifetimes.get(i).second;
+ int lifetimeLength = mNonLifetimes.get(i+1).first - offset;
+ long val;
+ switch (lifetimeLength) {
+ case 2: val = byteBuffer.getShort(offset); break;
+ case 4: val = byteBuffer.getInt(offset); break;
+ default: throw new IllegalStateException("bogus lifetime size " + length);
+ }
+ // Mask to size, converting signed to unsigned
+ val &= (1L << (lifetimeLength * 8)) - 1;
+ minLifetime = Math.min(minLifetime, val);
+ }
+ return minLifetime;
+ }
+
+ // How many seconds does this RA's have to live, taking into account the fact
+ // that we might have seen it a while ago.
+ long currentLifetime() {
+ return mMinLifetime - (curTime() - mLastSeen);
+ }
+
+ boolean isExpired() {
+ return currentLifetime() < 0;
+ }
+
+ // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped.
+ // Jump to the next filter if packet doesn't match this RA.
+ long generateFilter(ApfGenerator gen) throws IllegalInstructionException {
+ String nextFilterLabel = "Ra" + getUniqueNumber();
+ // Skip if packet is not the right size
+ gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
+ gen.addJumpIfR0NotEquals(mPacket.limit(), nextFilterLabel);
+ int filterLifetime = (int)(currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER);
+ // Skip filter if expired
+ gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
+ gen.addJumpIfR0GreaterThan(filterLifetime, nextFilterLabel);
+ for (int i = 0; i < mNonLifetimes.size(); i++) {
+ // Generate code to match the packet bytes
+ Pair<Integer, Integer> nonLifetime = mNonLifetimes.get(i);
+ gen.addLoadImmediate(Register.R0, nonLifetime.first);
+ gen.addJumpIfBytesNotEqual(Register.R0,
+ Arrays.copyOfRange(mPacket.array(), nonLifetime.first,
+ nonLifetime.first + nonLifetime.second),
+ nextFilterLabel);
+ // Generate code to test the lifetimes haven't gone down too far
+ if ((i + 1) < mNonLifetimes.size()) {
+ Pair<Integer, Integer> nextNonLifetime = mNonLifetimes.get(i + 1);
+ int offset = nonLifetime.first + nonLifetime.second;
+ int length = nextNonLifetime.first - offset;
+ switch (length) {
+ case 4: gen.addLoad32(Register.R0, offset); break;
+ case 2: gen.addLoad16(Register.R0, offset); break;
+ default: throw new IllegalStateException("bogus lifetime size " + length);
+ }
+ gen.addJumpIfR0LessThan(filterLifetime, nextFilterLabel);
+ }
+ }
+ gen.addJump(gen.DROP_LABEL);
+ gen.defineLabel(nextFilterLabel);
+ return filterLifetime;
+ }
+ }
+
+ // Maximum number of RAs to filter for.
+ private static final int MAX_RAS = 10;
+ private ArrayList<Ra> mRas = new ArrayList<Ra>();
+
+ // There is always some marginal benefit to updating the installed APF program when an RA is
+ // seen because we can extend the program's lifetime slightly, but there is some cost to
+ // updating the program, so don't bother unless the program is going to expire soon. This
+ // constant defines "soon" in seconds.
+ private static final long MAX_PROGRAM_LIFETIME_WORTH_REFRESHING = 30;
+ // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever
+ // see a refresh. Using half the lifetime might be a good idea except for the fact that
+ // packets may be dropped, so let's use 6.
+ private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6;
+
+ // When did we last install a filter program? In seconds since Unix Epoch.
+ private long mLastTimeInstalledProgram;
+ // How long should the last installed filter program live for? In seconds.
+ private long mLastInstalledProgramMinLifetime;
+
+ private void installNewProgram() {
+ if (mRas.size() == 0) return;
+ final byte[] program;
+ long programMinLifetime = Long.MAX_VALUE;
+ try {
+ ApfGenerator gen = new ApfGenerator();
+ // This is guaranteed to return true because of the check in maybeInstall.
+ gen.setApfVersion(mNai.networkMisc.apfVersionSupported);
+ // Step 1: Determine how many RA filters we can fit in the program.
+ int ras = 0;
+ for (Ra ra : mRas) {
+ if (ra.isExpired()) continue;
+ ra.generateFilter(gen);
+ if (gen.programLengthOverEstimate() > mNai.networkMisc.maximumApfProgramSize) {
+ // We went too far. Use prior number of RAs in "ras".
+ break;
+ } else {
+ // Yay! this RA filter fits, increment "ras".
+ ras++;
+ }
+ }
+ // Step 2: Generate RA filters
+ gen = new ApfGenerator();
+ // This is guaranteed to return true because of the check in maybeInstall.
+ gen.setApfVersion(mNai.networkMisc.apfVersionSupported);
+ for (Ra ra : mRas) {
+ if (ras-- == 0) break;
+ if (ra.isExpired()) continue;
+ programMinLifetime = Math.min(programMinLifetime, ra.generateFilter(gen));
+ }
+ // Execution will reach the end of the program if no filters match, which will pass the
+ // packet to the AP.
+ program = gen.generate();
+ } catch (IllegalInstructionException e) {
+ Log.e(TAG, "Program failed to generate: ", e);
+ return;
+ }
+ mLastTimeInstalledProgram = curTime();
+ mLastInstalledProgramMinLifetime = programMinLifetime;
+ hexDump("Installing filter: ", program, program.length);
+ mConnectivityService.pushApfProgramToNetwork(mNai, program);
+ }
+
+ // Install a new filter program if the last installed one will die soon.
+ private void maybeInstallNewProgram() {
+ if (mRas.size() == 0) return;
+ // If the current program doesn't expire for a while, don't bother updating.
+ long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime;
+ if (expiry < curTime() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING) {
+ installNewProgram();
+ }
+ }
+
+ private void hexDump(String msg, byte[] packet, int length) {
+ log(msg + HexDump.toHexString(packet, 0, length));
+ }
+
+ private void processRa(byte[] packet, int length) {
+ hexDump("Read packet = ", packet, length);
+
+ // Have we seen this RA before?
+ for (int i = 0; i < mRas.size(); i++) {
+ Ra ra = mRas.get(i);
+ if (ra.matches(packet, length)) {
+ log("matched RA");
+ // Update lifetimes.
+ ra.mLastSeen = curTime();
+ ra.mMinLifetime = ra.minLifetime(packet, length);
+
+ // Keep mRas in LRU order so as to prioritize generating filters for recently seen
+ // RAs. LRU prioritizes this because RA filters are generated in order from mRas
+ // until the filter program exceeds the maximum filter program size allowed by the
+ // chipset, so RAs appearing earlier in mRas are more likely to make it into the
+ // filter program.
+ // TODO: consider sorting the RAs in order of increasing expiry time as well.
+ // Swap to front of array.
+ mRas.add(0, mRas.remove(i));
+
+ maybeInstallNewProgram();
+ return;
+ }
+ }
+ // Purge expired RAs.
+ for (int i = 0; i < mRas.size();) {
+ if (mRas.get(i).isExpired()) {
+ log("expired RA");
+ mRas.remove(i);
+ } else {
+ i++;
+ }
+ }
+ // TODO: figure out how to proceed when we've received more then MAX_RAS RAs.
+ if (mRas.size() >= MAX_RAS) return;
+ try {
+ log("adding RA");
+ mRas.add(new Ra(packet, length));
+ } catch (Exception e) {
+ Log.e(TAG, "Error parsing RA: " + e);
+ return;
+ }
+ installNewProgram();
+ }
+
+ /**
+ * Install an {@link ApfFilter} on {@code nai} if {@code nai} supports packet
+ * filtering using APF programs.
+ */
+ public static void maybeInstall(ConnectivityService connectivityService, NetworkAgentInfo nai) {
+ if (nai.networkMisc == null) return;
+ if (nai.networkMisc.apfVersionSupported == 0) return;
+ if (nai.networkMisc.maximumApfProgramSize < 200) {
+ Log.e(TAG, "Uselessly small APF size limit: " + nai.networkMisc.maximumApfProgramSize);
+ return;
+ }
+ // For now only support generating programs for Ethernet frames. If this restriction is
+ // lifted:
+ // 1. the program generator will need its offsets adjusted.
+ // 2. the packet filter attached to our packet socket will need its offset adjusted.
+ if (nai.networkMisc.apfPacketFormat != ARPHRD_ETHER) return;
+ if (!new ApfGenerator().setApfVersion(nai.networkMisc.apfVersionSupported)) {
+ Log.e(TAG, "Unsupported APF version: " + nai.networkMisc.apfVersionSupported);
+ return;
+ }
+ nai.apfFilter = new ApfFilter(connectivityService, nai);
+ }
+
+ public void shutdown() {
+ if (mReceiveThread != null) {
+ log("shuting down");
+ mReceiveThread.halt(); // Also closes socket.
+ mReceiveThread = null;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 90c9ddf..9e1f6b8 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -60,7 +60,7 @@
public class KeepaliveTracker {
private static final String TAG = "KeepaliveTracker";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
public static final String PERMISSION = android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD;
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index a9eaeee..b390884 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -16,13 +16,11 @@
package com.android.server.connectivity;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_WIFI;
-
import java.net.Inet4Address;
import android.content.Context;
import android.net.InterfaceConfiguration;
+import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkAgent;
@@ -34,6 +32,7 @@
import android.util.Slog;
import com.android.server.net.BaseNetworkObserver;
+import com.android.internal.util.ArrayUtils;
/**
* @hide
@@ -46,6 +45,13 @@
// This must match the interface prefix in clatd.c.
private static final String CLAT_PREFIX = "v4-";
+ // The network types we will start clatd on.
+ private static final int[] NETWORK_TYPES = {
+ ConnectivityManager.TYPE_MOBILE,
+ ConnectivityManager.TYPE_WIFI,
+ ConnectivityManager.TYPE_ETHERNET,
+ };
+
private final INetworkManagementService mNMService;
// ConnectivityService Handler for LinkProperties updates.
@@ -90,7 +96,7 @@
(nai.linkProperties != null) ? nai.linkProperties.hasIPv4Address() : false;
// Only support clat on mobile and wifi for now, because these are the only IPv6-only
// networks we can connect to.
- return connected && !hasIPv4Address && (netType == TYPE_MOBILE || netType == TYPE_WIFI);
+ return connected && !hasIPv4Address && ArrayUtils.contains(NETWORK_TYPES, netType);
}
/**
@@ -221,7 +227,7 @@
}
private void maybeSetIpv6NdOffload(String iface, boolean on) {
- if (mNetwork.networkInfo.getType() != TYPE_WIFI) {
+ if (mNetwork.networkInfo.getType() != ConnectivityManager.TYPE_WIFI) {
return;
}
try {
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index c5d38cb..b4c71c1 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -32,6 +32,7 @@
import com.android.internal.util.AsyncChannel;
import com.android.server.ConnectivityService;
import com.android.server.connectivity.NetworkMonitor;
+import com.android.server.connectivity.ApfFilter;
import java.util.ArrayList;
import java.util.Comparator;
@@ -163,6 +164,8 @@
// Used by ConnectivityService to keep track of 464xlat.
public Nat464Xlat clatd;
+ public ApfFilter apfFilter;
+
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
NetworkMisc misc, NetworkRequest defaultRequest, ConnectivityService connService) {
@@ -175,6 +178,7 @@
currentScore = score;
networkMonitor = connService.createNetworkMonitor(context, handler, this, defaultRequest);
networkMisc = misc;
+ apfFilter.maybeInstall(connService, this);
}
/**
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index fb8b110..73da427 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -76,7 +76,7 @@
* {@hide}
*/
public class NetworkMonitor extends StateMachine {
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final String TAG = "NetworkMonitor";
private static final String DEFAULT_SERVER = "connectivitycheck.gstatic.com";
private static final int SOCKET_TIMEOUT_MS = 10000;
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index debda14..22cefd1 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -54,7 +54,7 @@
*/
public class PermissionMonitor {
private static final String TAG = "PermissionMonitor";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean SYSTEM = true;
private static final boolean NETWORK = false;
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 760b218..4eecc81 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -90,7 +90,7 @@
private Context mContext;
private final static String TAG = "Tethering";
- private final static boolean DBG = true;
+ private final static boolean DBG = false;
private final static boolean VDBG = false;
// TODO - remove both of these - should be part of interface inspection/selection stuff
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index ed68abe..e08fad4 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1559,11 +1559,11 @@
* called from native code to update SV info
*/
private void reportSvStatus() {
- int svCount = native_read_sv_status(mSvidWithFlags, mSnrs, mSvElevations, mSvAzimuths);
+ int svCount = native_read_sv_status(mSvidWithFlags, mCn0s, mSvElevations, mSvAzimuths);
mListenerHelper.onSvStatusChanged(
svCount,
mSvidWithFlags,
- mSnrs,
+ mCn0s,
mSvElevations,
mSvAzimuths);
@@ -1578,7 +1578,7 @@
}
if (VERBOSE) {
Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
- " snr: " + mSnrs[i]/10 +
+ " cn0: " + mCn0s[i]/10 +
" elev: " + mSvElevations[i] +
" azimuth: " + mSvAzimuths[i] +
((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
@@ -2402,7 +2402,7 @@
// preallocated arrays, to avoid memory allocation in reportStatus()
private int mSvidWithFlags[] = new int[MAX_SVS];
- private float mSnrs[] = new float[MAX_SVS];
+ private float mCn0s[] = new float[MAX_SVS];
private float mSvElevations[] = new float[MAX_SVS];
private float mSvAzimuths[] = new float[MAX_SVS];
private int mSvCount;
@@ -2424,7 +2424,7 @@
private native void native_delete_aiding_data(int flags);
// returns number of SVs
// mask[0] is ephemeris mask and mask[1] is almanac mask
- private native int native_read_sv_status(int[] prnWithFlags, float[] snrs, float[] elevations,
+ private native int native_read_sv_status(int[] prnWithFlags, float[] cn0s, float[] elevations,
float[] azimuths);
private native int native_read_nmea(byte[] buffer, int bufferSize);
private native void native_inject_location(double latitude, double longitude, float accuracy);
diff --git a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
index d9e8e91..734a8d4 100644
--- a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
@@ -72,7 +72,7 @@
status = GnssMeasurementsEvent.STATUS_NOT_SUPPORTED;
break;
case RESULT_GPS_LOCATION_DISABLED:
- status = GnssMeasurementsEvent.STATUS_GPS_LOCATION_DISABLED;
+ status = GnssMeasurementsEvent.STATUS_GNSS_LOCATION_DISABLED;
break;
case RESULT_UNKNOWN:
return null;
diff --git a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
index 57bce4b..fdef31f 100644
--- a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
+++ b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
@@ -73,7 +73,8 @@
status = GnssNavigationMessageEvent.STATUS_NOT_SUPPORTED;
break;
case RESULT_GPS_LOCATION_DISABLED:
- status = GnssNavigationMessageEvent.STATUS_GPS_LOCATION_DISABLED;
+ status = GnssNavigationMessageEvent
+ .STATUS_GNSS_LOCATION_DISABLED;
break;
case RESULT_UNKNOWN:
return null;
diff --git a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
index 0b3111c..d471e45 100644
--- a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
+++ b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
@@ -75,7 +75,7 @@
public void onSvStatusChanged(
final int svCount,
final int[] prnWithFlags,
- final float[] snrs,
+ final float[] cn0s,
final float[] elevations,
final float[] azimuths) {
Operation operation = new Operation() {
@@ -84,7 +84,7 @@
listener.onSvStatusChanged(
svCount,
prnWithFlags,
- snrs,
+ cn0s,
elevations,
azimuths);
}
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index 9f1435a..2807ec8 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -40,7 +40,7 @@
public class IpConfigStore {
private static final String TAG = "IpConfigStore";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
protected final DelayedDiskWrite mWriter;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 09b7a18..3acd2ca 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -42,6 +42,7 @@
import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
@@ -68,6 +69,7 @@
import static android.net.wifi.WifiManager.EXTRA_WIFI_CONFIGURATION;
import static android.net.wifi.WifiManager.EXTRA_WIFI_INFO;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
+
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
@@ -294,6 +296,7 @@
final SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
final SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
+ final SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
/** Set of states for the child firewall chains. True if the chain is active. */
final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
@@ -522,9 +525,11 @@
new PowerManagerInternal.LowPowerModeListener() {
@Override
public void onLowPowerModeChanged(boolean enabled) {
+ if (LOGD) Slog.d(TAG, "onLowPowerModeChanged(" + enabled + ")");
synchronized (mRulesLock) {
if (mRestrictPower != enabled) {
mRestrictPower = enabled;
+ updateRulesForRestrictPowerLocked();
updateRulesForGlobalChangeLocked(true);
}
}
@@ -1175,13 +1180,6 @@
return;
}
- // If we are in restrict power mode, we want to treat all interfaces
- // as metered, to restrict access to the network by uid. However, we
- // will not have a bandwidth limit. Also only do this if restrict
- // background data use is *not* enabled, since that takes precedence
- // use over those networks can have a cost associated with it).
- final boolean powerSave = mRestrictPower && !mRestrictBackground;
-
// First, generate identities of all connected networks so we can
// quickly compare them against all defined policies below.
final ArrayList<Pair<String, NetworkIdentity>> connIdents = new ArrayList<>(states.length);
@@ -1193,9 +1191,6 @@
final String baseIface = state.linkProperties.getInterfaceName();
if (baseIface != null) {
connIdents.add(Pair.create(baseIface, ident));
- if (powerSave) {
- connIfaces.add(baseIface);
- }
}
// Stacked interfaces are considered to have same identity as
@@ -1205,9 +1200,6 @@
final String stackedIface = stackedLink.getInterfaceName();
if (stackedIface != null) {
connIdents.add(Pair.create(stackedIface, ident));
- if (powerSave) {
- connIfaces.add(stackedIface);
- }
}
}
}
@@ -1254,8 +1246,7 @@
}
if (LOGD) {
- Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces "
- + Arrays.toString(ifaces));
+ Slog.d(TAG, "applying policy " + policy + " to ifaces " + Arrays.toString(ifaces));
}
final boolean hasWarning = policy.warningBytes != LIMIT_DISABLED;
@@ -1286,9 +1277,6 @@
removeInterfaceQuota(iface);
setInterfaceQuota(iface, quotaBytes);
newMeteredIfaces.add(iface);
- if (powerSave) {
- connIfaces.remove(iface);
- }
}
}
@@ -1631,7 +1619,7 @@
try {
final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
if (oldPolicy != policy) {
- setUidPolicyUncheckedLocked(uid, policy, true);
+ setUidPolicyUncheckedLocked(uid, oldPolicy, policy, true);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -1651,7 +1639,7 @@
final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
policy |= oldPolicy;
if (oldPolicy != policy) {
- setUidPolicyUncheckedLocked(uid, policy, true);
+ setUidPolicyUncheckedLocked(uid, oldPolicy, policy, true);
}
}
}
@@ -1668,11 +1656,22 @@
final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
policy = oldPolicy & ~policy;
if (oldPolicy != policy) {
- setUidPolicyUncheckedLocked(uid, policy, true);
+ setUidPolicyUncheckedLocked(uid, oldPolicy, policy, true);
}
}
}
+ private void setUidPolicyUncheckedLocked(int uid, int oldPolicy, int policy, boolean persist) {
+ setUidPolicyUncheckedLocked(uid, policy, persist);
+
+ // Checks if app was added or removed to the blacklist.
+ if ((oldPolicy == POLICY_NONE && policy == POLICY_REJECT_METERED_BACKGROUND)
+ || (oldPolicy == POLICY_REJECT_METERED_BACKGROUND && policy == POLICY_NONE)) {
+ mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
+ .sendToTarget();
+ }
+ }
+
private void setUidPolicyUncheckedLocked(int uid, int policy, boolean persist) {
mUidPolicy.put(uid, policy);
@@ -2000,7 +1999,20 @@
public int getRestrictBackgroundByCaller() {
mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
final int uid = Binder.getCallingUid();
+
synchronized (mRulesLock) {
+ // Must clear identity because getUidPolicy() is restricted to system.
+ final long token = Binder.clearCallingIdentity();
+ final int policy;
+ try {
+ policy = getUidPolicy(uid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ if (policy == POLICY_REJECT_METERED_BACKGROUND) {
+ // App is blacklisted.
+ return RESTRICT_BACKGROUND_STATUS_ENABLED;
+ }
if (!mRestrictBackground) {
return RESTRICT_BACKGROUND_STATUS_DISABLED;
}
@@ -2299,9 +2311,14 @@
// state changed, push updated rules
mUidState.put(uid, uidState);
updateRulesForUidStateChangeLocked(uid, oldUidState, uidState);
- if (mDeviceIdleMode && isProcStateAllowedWhileIdle(oldUidState)
- != isProcStateAllowedWhileIdle(uidState)) {
- updateRuleForDeviceIdleLocked(uid);
+ if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
+ != isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
+ if (mDeviceIdleMode) {
+ updateRuleForDeviceIdleLocked(uid);
+ }
+ if (mRestrictPower) {
+ updateRulesForRestrictPowerLocked(uid);
+ }
}
}
}
@@ -2317,6 +2334,9 @@
if (mDeviceIdleMode) {
updateRuleForDeviceIdleLocked(uid);
}
+ if (mRestrictPower) {
+ updateRulesForRestrictPowerLocked(uid);
+ }
}
}
}
@@ -2354,15 +2374,36 @@
}
}
- static boolean isProcStateAllowedWhileIdle(int procState) {
+ static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(int procState) {
return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
}
+ void updateRulesForRestrictPowerLocked() {
+ updateRulesForWhitelistedPowerSaveLocked(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
+ mUidFirewallPowerSaveRules);
+ }
+
+ void updateRulesForRestrictPowerLocked(int uid) {
+ updateRulesForWhitelistedPowerSaveLocked(uid, mRestrictPower, FIREWALL_CHAIN_POWERSAVE);
+ }
+
void updateRulesForDeviceIdleLocked() {
- if (mDeviceIdleMode) {
- // sync the whitelists before enable dozable chain. We don't care about the rules if
+ updateRulesForWhitelistedPowerSaveLocked(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
+ mUidFirewallDozableRules);
+ }
+
+ void updateRuleForDeviceIdleLocked(int uid) {
+ updateRulesForWhitelistedPowerSaveLocked(uid, mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE);
+ }
+
+ // NOTE: since both fw_dozable and fw_powersave uses the same map (mPowerSaveTempWhitelistAppIds)
+ // for whitelisting, we can reuse their logic in this method.
+ private void updateRulesForWhitelistedPowerSaveLocked(boolean enabled, int chain,
+ SparseIntArray rules) {
+ if (enabled) {
+ // Sync the whitelists before enabling the chain. We don't care about the rules if
// we are disabling the chain.
- final SparseIntArray uidRules = mUidFirewallDozableRules;
+ final SparseIntArray uidRules = rules;
uidRules.clear();
final List<UserInfo> users = mUserManager.getUsers();
for (int ui = users.size() - 1; ui >= 0; ui--) {
@@ -2381,24 +2422,26 @@
}
}
for (int i = mUidState.size() - 1; i >= 0; i--) {
- if (isProcStateAllowedWhileIdle(mUidState.valueAt(i))) {
+ if (isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.valueAt(i))) {
uidRules.put(mUidState.keyAt(i), FIREWALL_RULE_ALLOW);
}
}
- setUidFirewallRules(FIREWALL_CHAIN_DOZABLE, uidRules);
+ setUidFirewallRules(chain, uidRules);
}
- enableFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode);
+ enableFirewallChainLocked(chain, enabled);
}
- void updateRuleForDeviceIdleLocked(int uid) {
- if (mDeviceIdleMode) {
+ // NOTE: since both fw_dozable and fw_powersave uses the same map (mPowerSaveTempWhitelistAppIds)
+ // for whitelisting, we can reuse their logic in this method.
+ private void updateRulesForWhitelistedPowerSaveLocked(int uid, boolean enabled, int chain) {
+ if (enabled) {
int appId = UserHandle.getAppId(uid);
if (mPowerSaveTempWhitelistAppIds.get(appId) || mPowerSaveWhitelistAppIds.get(appId)
- || isProcStateAllowedWhileIdle(mUidState.get(uid))) {
- setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_ALLOW);
+ || isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.get(uid))) {
+ setUidFirewallRule(chain, uid, FIREWALL_RULE_ALLOW);
} else {
- setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT);
+ setUidFirewallRule(chain, uid, FIREWALL_RULE_DEFAULT);
}
}
@@ -2454,10 +2497,14 @@
* {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value.
*/
void updateRulesForGlobalChangeLocked(boolean restrictedNetworksChanged) {
+ long start;
+ if (LOGD) start = System.currentTimeMillis();
+
final PackageManager pm = mContext.getPackageManager();
updateRulesForDeviceIdleLocked();
updateRulesForAppIdleLocked();
+ updateRulesForRestrictPowerLocked();
// update rules for all installed applications
final List<UserInfo> users = mUserManager.getUsers();
@@ -2465,8 +2512,12 @@
PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS
| PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
- for (UserInfo user : users) {
- for (ApplicationInfo app : apps) {
+ final int usersSize = users.size();
+ final int appsSize = apps.size();
+ for (int i = 0; i < usersSize; i++) {
+ final UserInfo user = users.get(i);
+ for (int j = 0; j < appsSize; j++) {
+ final ApplicationInfo app = apps.get(j);
final int uid = UserHandle.getUid(user.id, app.uid);
updateRulesForUidLocked(uid);
}
@@ -2481,16 +2532,23 @@
normalizePoliciesLocked();
updateNetworkRulesLocked();
}
+ if (LOGD) {
+ final long delta = System.currentTimeMillis() - start;
+ Slog.d(TAG, "updateRulesForGlobalChangeLocked(" + restrictedNetworksChanged + ") took "
+ + delta + "ms");
+ }
}
void updateRulesForTempWhitelistChangeLocked() {
final List<UserInfo> users = mUserManager.getUsers();
- for (UserInfo user : users) {
- for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) {
- int appId = mPowerSaveTempWhitelistAppIds.keyAt(i);
+ for (int i = 0; i < users.size(); i++) {
+ final UserInfo user = users.get(i);
+ for (int j = mPowerSaveTempWhitelistAppIds.size() - 1; j >= 0; j--) {
+ int appId = mPowerSaveTempWhitelistAppIds.keyAt(j);
int uid = UserHandle.getUid(user.id, appId);
updateRuleForAppIdleLocked(uid);
updateRuleForDeviceIdleLocked(uid);
+ updateRulesForRestrictPowerLocked(uid);
}
}
}
@@ -2583,6 +2641,12 @@
uidRules = RULE_REJECT_ALL;
}
+ // Check powersave state, which is whitelist
+ if (mFirewallChainStates.get(FIREWALL_CHAIN_POWERSAVE)
+ && mUidFirewallPowerSaveRules.get(uid, FIREWALL_RULE_DEFAULT) != FIREWALL_RULE_ALLOW) {
+ uidRules = RULE_REJECT_ALL;
+ }
+
// Check standby state, which is blacklist
if (mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY)
&& mUidFirewallStandbyRules.get(uid, FIREWALL_RULE_DEFAULT) == FIREWALL_RULE_DENY) {
@@ -2810,6 +2874,8 @@
mUidFirewallDozableRules.put(uid, rule);
} else if (chain == FIREWALL_CHAIN_STANDBY) {
mUidFirewallStandbyRules.put(uid, rule);
+ } else if (chain == FIREWALL_CHAIN_POWERSAVE) {
+ mUidFirewallPowerSaveRules.put(uid, rule);
}
try {
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index 5e4703d..7dff2c1 100644
--- a/services/core/java/com/android/server/notification/NotificationComparator.java
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -28,10 +28,11 @@
final int leftImportance = left.getImportance();
final int rightImportance = right.getImportance();
if (leftImportance != rightImportance) {
- // by priority, high to low
+ // by importance, high to low
return -1 * Integer.compare(leftImportance, rightImportance);
}
+ // Whether or not the notification can bypass DND.
final int leftPackagePriority = left.getPackagePriority();
final int rightPackagePriority = right.getPackagePriority();
if (leftPackagePriority != rightPackagePriority) {
@@ -39,6 +40,13 @@
return -1 * Integer.compare(leftPackagePriority, rightPackagePriority);
}
+ final int leftPriority = left.sbn.getNotification().priority;
+ final int rightPriority = right.sbn.getNotification().priority;
+ if (leftPriority != rightPriority) {
+ // by priority, high to low
+ return -1 * Integer.compare(leftPriority, rightPriority);
+ }
+
final float leftPeople = left.getContactAffinity();
final float rightPeople = right.getContactAffinity();
if (leftPeople != rightPeople) {
diff --git a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
index b57cc75..bcdeb66 100644
--- a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
+++ b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
@@ -23,7 +23,7 @@
import android.util.Slog;
/**
- * This {@link com.android.server.notification.NotificationSignalExtractor} noticies noisy
+ * This {@link com.android.server.notification.NotificationSignalExtractor} notices noisy
* notifications and marks them to get a temporary ranking bump.
*/
public class NotificationIntrusivenessExtractor implements NotificationSignalExtractor {
@@ -44,9 +44,15 @@
return null;
}
- final Notification notification = record.getNotification();
- if (record.getImportance() > NotificationListenerService.Ranking.IMPORTANCE_DEFAULT) {
- record.setRecentlyIntrusive(true);
+ if (record.getImportance() >= NotificationListenerService.Ranking.IMPORTANCE_DEFAULT) {
+ final Notification notification = record.getNotification();
+ if ((notification.defaults & Notification.DEFAULT_VIBRATE) != 0 ||
+ notification.vibrate != null ||
+ (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
+ notification.sound != null ||
+ notification.fullScreenIntent != null) {
+ record.setRecentlyIntrusive(true);
+ }
}
return new RankingReconsideration(record.getKey(), HANG_TIME_MS) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e8d27db..3855579 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1320,7 +1320,7 @@
@Override
public int getImportance(String pkg, int uid) {
- checkCallerIsSystem();
+ enforceSystemOrSystemUI("Caller not system or systemui");
return mRankingHelper.getImportance(pkg, uid);
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 1476e6e..93dcc72 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -203,6 +203,11 @@
mInstaller.execute("linkfile", relativePath, fromBase, toBase);
}
+ public void moveAb(String apkPath, String instructionSet, String outputPath)
+ throws InstallerException {
+ mInstaller.execute("move_ab", apkPath, instructionSet, outputPath);
+ }
+
private static void assertValidInstructionSet(String instructionSet)
throws InstallerException {
for (String abi : Build.SUPPORTED_ABIS) {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 94b3b2d..67aeed1 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -16,36 +16,28 @@
package com.android.server.pm;
-import android.app.AppGlobals;
+import static com.android.server.pm.Installer.DEXOPT_OTA;
+import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+
import android.content.Context;
-import android.content.Intent;
import android.content.pm.IOtaDexopt;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.Package;
-import android.content.pm.ResolveInfo;
import android.os.Environment;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
-import android.os.UserHandle;
import android.os.storage.StorageManager;
-import android.util.ArraySet;
import android.util.Log;
+import android.util.Slog;
-import dalvik.system.DexFile;
+import com.android.internal.os.InstallerConnection.InstallerException;
import java.io.File;
import java.io.FileDescriptor;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
-import java.util.Set;
-
-import static com.android.server.pm.Installer.DEXOPT_OTA;
/**
* A service for A/B OTA dexopting.
@@ -70,6 +62,9 @@
// Use the package manager install and install lock here for the OTA dex optimizer.
mPackageDexOptimizer = new OTADexoptPackageDexOptimizer(packageManagerService.mInstaller,
packageManagerService.mInstallLock, context);
+
+ // Now it's time to check whether we need to move any A/B artifacts.
+ moveAbArtifacts(packageManagerService.mInstaller);
}
public static OtaDexoptService main(Context context,
@@ -150,20 +145,50 @@
false /* extractOnly */);
}
- private ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
- List<ResolveInfo> ris = null;
- try {
- ris = AppGlobals.getPackageManager().queryIntentReceivers(
- intent, null, 0, userId);
- } catch (RemoteException e) {
+ private void moveAbArtifacts(Installer installer) {
+ if (mDexoptPackages != null) {
+ throw new IllegalStateException("Should not be ota-dexopting when trying to move.");
}
- ArraySet<String> pkgNames = new ArraySet<String>(ris == null ? 0 : ris.size());
- if (ris != null) {
- for (ResolveInfo ri : ris) {
- pkgNames.add(ri.activityInfo.packageName);
+
+ // Look into all packages.
+ Collection<PackageParser.Package> pkgs = mPackageManagerService.getPackages();
+ for (PackageParser.Package pkg : pkgs) {
+ if (pkg == null) {
+ continue;
+ }
+
+ // Does the package have code? If not, there won't be any artifacts.
+ if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
+ continue;
+ }
+ if (pkg.codePath == null) {
+ Slog.w(TAG, "Package " + pkg + " can be optimized but has null codePath");
+ continue;
+ }
+
+ // If the path is in /system or /vendor, ignore. It will have been ota-dexopted into
+ // /data/ota and moved into the dalvik-cache already.
+ if (pkg.codePath.startsWith("/system") || pkg.codePath.startsWith("/vendor")) {
+ continue;
+ }
+
+ final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
+ final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
+ final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+ for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+ for (String path : paths) {
+ String oatDir = PackageDexOptimizer.getOatDir(new File(pkg.codePath)).
+ getAbsolutePath();
+
+ // TODO: Check first whether there is an artifact, to save the roundtrip time.
+
+ try {
+ installer.moveAb(path, dexCodeInstructionSet, oatDir);
+ } catch (InstallerException e) {
+ }
+ }
}
}
- return pkgNames;
}
private static class OTADexoptPackageDexOptimizer extends
@@ -180,10 +205,5 @@
return dexoptFlags | DEXOPT_OTA;
}
- @Override
- protected void recordSuccessfulDexopt(Package pkg, String instructionSet) {
- // Never record the dexopt, as it's in the B partition.
- }
-
}
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index a084d86..c9613b4 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -113,15 +113,6 @@
}
/**
- * Determine whether the package should be skipped for the given instruction set. A return
- * value of true means the package will be skipped. A return value of false means that the
- * package will be further investigated, and potentially compiled.
- */
- protected boolean shouldSkipBasedOnISA(PackageParser.Package pkg, String instructionSet) {
- return pkg.mDexOptPerformed.contains(instructionSet);
- }
-
- /**
* Adjust the given dexopt-needed value. Can be overridden to influence the decision to
* optimize or not (and in what way).
*/
@@ -136,13 +127,6 @@
return dexoptFlags;
}
- /**
- * Update the package status after a successful compilation.
- */
- protected void recordSuccessfulDexopt(PackageParser.Package pkg, String instructionSet) {
- pkg.mDexOptPerformed.add(instructionSet);
- }
-
private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
boolean useProfiles, boolean extractOnly) {
final String[] instructionSets = targetInstructionSets != null ?
@@ -159,11 +143,6 @@
boolean performedDexOpt = false;
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
- if (!useProfiles && shouldSkipBasedOnISA(pkg, dexCodeInstructionSet)) {
- // Skip only if we do not use profiles since they might trigger a recompilation.
- continue;
- }
-
for (String path : paths) {
if (useProfiles && isUsedByOtherApps(path)) {
// We cannot use profile guided compilation if the apk was used by another app.
@@ -172,35 +151,44 @@
int dexoptNeeded;
try {
- dexoptNeeded = DexFile.getDexOptNeeded(path, pkg.packageName,
- dexCodeInstructionSet, /* defer */false);
+ int compilationTypeMask = 0;
+ if (extractOnly) {
+ // For extract only, any type of compilation is good.
+ compilationTypeMask = DexFile.COMPILATION_TYPE_FULL
+ | DexFile.COMPILATION_TYPE_PROFILE_GUIDE
+ | DexFile.COMPILATION_TYPE_EXTRACT_ONLY;
+ } else {
+ // Branch taken for profile guide and full compilation.
+ // Profile guide compilation should only recompile a previous
+ // profile compiled/extract only file and should not be attempted if the
+ // apk is already fully compiled. So test against a full compilation type.
+ compilationTypeMask = DexFile.COMPILATION_TYPE_FULL;
+ }
+ dexoptNeeded = DexFile.getDexOptNeeded(path,
+ dexCodeInstructionSet, compilationTypeMask);
} catch (IOException ioe) {
Slog.w(TAG, "IOException reading apk: " + path, ioe);
return DEX_OPT_FAILED;
}
dexoptNeeded = adjustDexoptNeeded(dexoptNeeded);
- if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
- if (useProfiles) {
- // Profiles may trigger re-compilation. The final decision is taken in
- // installd.
- dexoptNeeded = DexFile.DEX2OAT_NEEDED;
- } else {
- // No dexopt needed and we don't use profiles. Nothing to do.
- continue;
- }
- }
final String dexoptType;
String oatDir = null;
- if (dexoptNeeded == DexFile.DEX2OAT_NEEDED) {
- dexoptType = "dex2oat";
- oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
- } else if (dexoptNeeded == DexFile.PATCHOAT_NEEDED) {
- dexoptType = "patchoat";
- } else if (dexoptNeeded == DexFile.SELF_PATCHOAT_NEEDED) {
- dexoptType = "self patchoat";
- } else {
- throw new IllegalStateException("Invalid dexopt needed: " + dexoptNeeded);
+ switch (dexoptNeeded) {
+ case DexFile.NO_DEXOPT_NEEDED:
+ continue;
+ case DexFile.DEX2OAT_NEEDED:
+ dexoptType = "dex2oat";
+ oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
+ break;
+ case DexFile.PATCHOAT_NEEDED:
+ dexoptType = "patchoat";
+ break;
+ case DexFile.SELF_PATCHOAT_NEEDED:
+ dexoptType = "self patchoat";
+ break;
+ default:
+ throw new IllegalStateException("Invalid dexopt:" + dexoptNeeded);
}
@@ -226,15 +214,6 @@
Slog.w(TAG, "Failed to dexopt", e);
}
}
-
- if (!extractOnly) {
- // At this point we haven't failed dexopt and we haven't deferred dexopt. We must
- // either have either succeeded dexopt, or have had getDexOptNeeded tell us
- // it isn't required. We therefore mark that this package doesn't need dexopt unless
- // it's forced. performedDexOpt will tell us whether we performed dex-opt or skipped
- // it.
- recordSuccessfulDexopt(pkg, dexCodeInstructionSet);
- }
}
// If we've gotten here, we're sure that no error occurred and that we haven't
@@ -317,12 +296,6 @@
}
@Override
- protected boolean shouldSkipBasedOnISA(Package pkg, String instructionSet) {
- // Forced compilation, never skip.
- return false;
- }
-
- @Override
protected int adjustDexoptNeeded(int dexoptNeeded) {
// Ensure compilation, no matter the current state.
// TODO: The return value is wrong when patchoat is needed.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bafcb64..b2ee0b2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -103,6 +103,7 @@
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
+import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.IDevicePolicyManager;
import android.app.backup.IBackupManager;
import android.content.BroadcastReceiver;
@@ -360,6 +361,7 @@
static final int SCAN_MOVE = 1<<13;
static final int SCAN_INITIAL = 1<<14;
static final int SCAN_CHECK_ONLY = 1<<15;
+ static final int SCAN_DONT_KILL_APP = 1<<17;
static final int REMOVE_CHATTY = 1<<16;
@@ -499,6 +501,9 @@
final ArrayMap<String, PackageParser.Package> mPackages =
new ArrayMap<String, PackageParser.Package>();
+ final ArrayMap<String, Set<String>> mKnownCodebase =
+ new ArrayMap<String, Set<String>>();
+
// Tracks available target package names -> overlay package paths.
final ArrayMap<String, ArrayMap<String, PackageParser.Package>> mOverlays =
new ArrayMap<String, ArrayMap<String, PackageParser.Package>>();
@@ -639,9 +644,6 @@
// List of packages names to keep cached, even if they are uninstalled for all users
private List<String> mKeepUninstalledPackages;
- private boolean mUseJitProfiles =
- SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
-
private static class IFVerificationParams {
PackageParser.Package pkg;
boolean replacing;
@@ -1428,19 +1430,21 @@
final boolean grantPermissions = (args.installFlags
& PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
+ final boolean killApp = (args.installFlags
+ & PackageManager.INSTALL_DONT_KILL_APP) == 0;
final String[] grantedPermissions = args.installGrantPermissions;
// Handle the parent package
- handlePackagePostInstall(parentRes, grantPermissions, grantedPermissions,
- args.observer);
+ handlePackagePostInstall(parentRes, grantPermissions, killApp,
+ grantedPermissions, args.observer);
// Handle the child packages
final int childCount = (parentRes.addedChildPackages != null)
? parentRes.addedChildPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
- handlePackagePostInstall(childRes, grantPermissions, grantedPermissions,
- args.observer);
+ handlePackagePostInstall(childRes, grantPermissions, killApp,
+ grantedPermissions, args.observer);
}
// Log tracing if needed
@@ -1635,11 +1639,12 @@
}
private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
- String[] grantedPermissions, IPackageInstallObserver2 installObserver) {
+ boolean killApp, String[] grantedPermissions,
+ IPackageInstallObserver2 installObserver) {
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
// Send the removed broadcasts
if (res.removedInfo != null) {
- res.removedInfo.sendPackageRemovedBroadcasts();
+ res.removedInfo.sendPackageRemovedBroadcasts(killApp);
}
// Now that we successfully installed the package, grant runtime
@@ -2161,10 +2166,12 @@
}
try {
- int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false);
+ // Shared libraries do not have profiles so we perform a full
+ // AOT compilation (if needed).
+ int dexoptNeeded = DexFile.getDexOptNeeded(
+ lib, dexCodeInstructionSet,
+ DexFile.COMPILATION_TYPE_FULL);
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
- // Shared libraries do not have profiles so we perform a full
- // AOT compilation.
mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,
dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/,
StorageManager.UUID_PRIVATE_INTERNAL,
@@ -4234,7 +4241,8 @@
// TODO: remove these terrible hacks
if (actionName.startsWith("android.net.netmon.lingerExpired")
|| actionName.startsWith("com.android.server.sip.SipWakeupTimer")
- || actionName.startsWith("com.android.internal.telephony.data-reconnect")) {
+ || actionName.startsWith("com.android.internal.telephony.data-reconnect")
+ || actionName.startsWith("android.net.netmon.launchCaptivePortalApp")) {
return true;
}
}
@@ -6837,7 +6845,7 @@
// Extract pacakges only if profile-guided compilation is enabled because
// otherwise BackgroundDexOptService will not dexopt them later.
- if (!mUseJitProfiles || !isUpgrade()) {
+ if (!isUpgrade()) {
return;
}
@@ -6919,10 +6927,6 @@
targetInstructionSet = instructionSet != null ? instructionSet :
getPrimaryInstructionSet(p.applicationInfo);
- if (!force && !useProfiles && p.mDexOptPerformed.contains(targetInstructionSet)) {
- // Skip only if we do not use profiles since they might trigger a recompilation.
- return false;
- }
}
long callingId = Binder.clearCallingIdentity();
try {
@@ -7903,13 +7907,17 @@
// Request the ActivityManager to kill the process(only for existing packages)
// so that we do not end up in a confused state while the user is still using the older
// version of the application while the new one gets installed.
- if ((scanFlags & SCAN_REPLACING) != 0) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "killApplication");
+ final boolean isReplacing = (scanFlags & SCAN_REPLACING) != 0;
+ final boolean killApp = (scanFlags & SCAN_DONT_KILL_APP) == 0;
+ if (killApp) {
+ if (isReplacing) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "killApplication");
- killApplication(pkg.applicationInfo.packageName,
- pkg.applicationInfo.uid, "replace pkg");
+ killApplication(pkg.applicationInfo.packageName,
+ pkg.applicationInfo.uid, "replace pkg");
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
}
// Also need to kill any apps that are dependent on the library.
@@ -10598,7 +10606,7 @@
info.removedPackage = packageName;
info.removedUsers = new int[] {userId};
info.uid = UserHandle.getUid(userId, pkgSetting.appId);
- info.sendPackageRemovedBroadcasts();
+ info.sendPackageRemovedBroadcasts(true /*killApp*/);
}
private void sendPackagesSuspendedForUser(String[] pkgList, int userId, boolean suspended) {
@@ -13081,6 +13089,15 @@
}
}
+ public List<String> getPreviousCodePaths(String packageName) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final List<String> result = new ArrayList<String>();
+ if (ps != null && ps.oldCodePaths != null) {
+ result.addAll(ps.oldCodePaths);
+ }
+ return result;
+ }
+
private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user,
int[] allUsers, String installerPackageName, PackageInstalledInfo res) {
@@ -13090,12 +13107,16 @@
String pkgName = deletedPackage.packageName;
boolean deletedPkg = true;
boolean addedPkg = false;
+ boolean updatedSettings = false;
+ final boolean killApp = (scanFlags & SCAN_DONT_KILL_APP) == 0;
+ final int deleteFlags = PackageManager.DELETE_KEEP_DATA
+ | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
final long origUpdateTime = (pkg.mExtras != null)
? ((PackageSetting)pkg.mExtras).lastUpdateTime : 0;
// First delete the existing package while retaining the data directory
- if (!deletePackageLI(pkgName, null, true, allUsers, PackageManager.DELETE_KEEP_DATA,
+ if (!deletePackageLI(pkgName, null, true, allUsers, deleteFlags,
res.removedInfo, true, pkg)) {
// If the existing package wasn't successfully deleted
res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE, "replaceNonSystemPackageLI");
@@ -13121,6 +13142,27 @@
final PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags,
scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
updateSettingsLI(newPackage, installerPackageName, allUsers, res, user);
+
+ // Update the in-memory copy of the previous code paths.
+ PackageSetting ps = mSettings.mPackages.get(pkgName);
+ if (!killApp) {
+ if (ps.oldCodePaths == null) {
+ ps.oldCodePaths = new ArraySet<>();
+ }
+ Collections.addAll(ps.oldCodePaths, deletedPackage.baseCodePath);
+ if (deletedPackage.splitCodePaths != null) {
+ Collections.addAll(ps.oldCodePaths, deletedPackage.splitCodePaths);
+ }
+ } else {
+ ps.oldCodePaths = null;
+ }
+ if (ps.childPackageNames != null) {
+ for (int i = ps.childPackageNames.size() - 1; i >= 0; --i) {
+ final String childPkgName = ps.childPackageNames.get(i);
+ final PackageSetting childPs = mSettings.mPackages.get(childPkgName);
+ childPs.oldCodePaths = ps.oldCodePaths;
+ }
+ }
prepareAppDataAfterInstall(newPackage);
addedPkg = true;
} catch (PackageManagerException e) {
@@ -13133,7 +13175,7 @@
// Revert all internal state mutations and added folders for the failed install
if (addedPkg) {
- deletePackageLI(pkgName, null, true, allUsers, PackageManager.DELETE_KEEP_DATA,
+ deletePackageLI(pkgName, null, true, allUsers, deleteFlags,
res.removedInfo, true, null);
}
@@ -13586,6 +13628,9 @@
// moving a complete application; perform an initial scan on the new install location
scanFlags |= SCAN_INITIAL;
}
+ if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
+ scanFlags |= SCAN_DONT_KILL_APP;
+ }
// Result object to be returned
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
@@ -13852,21 +13897,17 @@
return;
}
- // Extract package to save the VM unzipping the APK in memory during
- // launch. Only do this if profile-guided compilation is enabled because
- // otherwise BackgroundDexOptService will not dexopt the package later.
- if (mUseJitProfiles) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
- // Do not run PackageDexOptimizer through the local performDexOpt
- // method because `pkg` is not in `mPackages` yet.
- int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instructionSets */,
- false /* useProfiles */, true /* extractOnly */);
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
- String msg = "Extracking package failed for " + pkgName;
- res.setError(INSTALL_FAILED_DEXOPT, msg);
- return;
- }
+
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+ // Do not run PackageDexOptimizer through the local performDexOpt
+ // method because `pkg` is not in `mPackages` yet.
+ int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instructionSets */,
+ false /* useProfiles */, true /* extractOnly */);
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
+ String msg = "Extracking package failed for " + pkgName;
+ res.setError(INSTALL_FAILED_DEXOPT, msg);
+ return;
}
}
@@ -14310,7 +14351,8 @@
}
if (res) {
- info.sendPackageRemovedBroadcasts();
+ final boolean killApp = (flags & PackageManager.INSTALL_DONT_KILL_APP) == 0;
+ info.sendPackageRemovedBroadcasts(killApp);
info.sendSystemPackageUpdatedBroadcasts();
info.sendSystemPackageAppearedBroadcasts();
}
@@ -14342,12 +14384,12 @@
ArrayMap<String, PackageRemovedInfo> removedChildPackages;
ArrayMap<String, PackageInstalledInfo> appearedChildPackages;
- void sendPackageRemovedBroadcasts() {
- sendPackageRemovedBroadcastInternal();
+ void sendPackageRemovedBroadcasts(boolean killApp) {
+ sendPackageRemovedBroadcastInternal(killApp);
final int childCount = removedChildPackages != null ? removedChildPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageRemovedInfo childInfo = removedChildPackages.valueAt(i);
- childInfo.sendPackageRemovedBroadcastInternal();
+ childInfo.sendPackageRemovedBroadcastInternal(killApp);
}
}
@@ -14389,10 +14431,11 @@
null, 0, removedPackage, null, null);
}
- private void sendPackageRemovedBroadcastInternal() {
+ private void sendPackageRemovedBroadcastInternal(boolean killApp) {
Bundle extras = new Bundle(2);
extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved);
+ extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
if (isUpdate || isRemovedPackageSystemUpdate) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
@@ -14883,7 +14926,10 @@
} else {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
// Kill application pre-emptively especially for apps on sd.
- killApplication(packageName, ps.appId, "uninstall pkg");
+ final boolean killApp = (flags & PackageManager.DELETE_DONT_KILL_APP) == 0;
+ if (killApp) {
+ killApplication(packageName, ps.appId, "uninstall pkg");
+ }
ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags, allUserHandles,
outInfo, writeSettings, replacingPackage);
}
@@ -15065,8 +15111,15 @@
final IPackageDataObserver observer, final int userId) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CLEAR_APP_USER_DATA, null);
+
enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */, "clear application data");
+
+ final DevicePolicyManagerInternal dpmi = LocalServices
+ .getService(DevicePolicyManagerInternal.class);
+ if (dpmi != null && dpmi.hasDeviceOwnerOrProfileOwner(packageName, userId)) {
+ throw new SecurityException("Cannot clear data for a device owner or a profile owner");
+ }
// Queue up an async operation since the package deletion may take a little while.
mHandler.post(new Runnable() {
public void run() {
@@ -15078,8 +15131,8 @@
clearExternalStorageDataSync(packageName, userId, true);
if (succeeded) {
// invoke DeviceStorageMonitor's update method to clear any notifications
- DeviceStorageMonitorInternal
- dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
+ DeviceStorageMonitorInternal dsm = LocalServices
+ .getService(DeviceStorageMonitorInternal.class);
if (dsm != null) {
dsm.checkMemory();
}
@@ -19132,6 +19185,11 @@
return permissionsState.isPermissionReviewRequired(userId);
}
}
+
+ @Override
+ public ApplicationInfo getApplicationInfo(String packageName, int userId) {
+ return PackageManagerService.this.getApplicationInfo(packageName, 0 /*flags*/, userId);
+ }
}
@Override
@@ -19159,4 +19217,14 @@
boolean isHistoricalPackageUsageAvailable() {
return mPackageUsage.isHistoricalPackageUsageAvailable();
}
+
+ /**
+ * Return a <b>copy</b> of the collection of packages known to the package manager.
+ * @return A copy of the values of mPackages.
+ */
+ Collection<PackageParser.Package> getPackages() {
+ synchronized (mPackages) {
+ return new ArrayList<>(mPackages.values());
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index e5eec7e..1434718 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -30,6 +30,7 @@
import java.io.File;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
/**
* Settings base class for pending and resolved classes.
@@ -118,7 +119,14 @@
* platform will refuse to launch packages in a frozen state.
*/
boolean frozen = false;
-
+ /**
+ * Non-persisted value. During an "upgrade without restart", we need the set
+ * of all previous code paths so we can surgically add the new APKs to the
+ * active classloader. If at any point an application is upgraded with a
+ * restart, this field will be cleared since the classloader would be created
+ * using the full set of code paths when the package's process is started.
+ */
+ Set<String> oldCodePaths;
PackageSettingBase origPackage;
/** Package name of the app that installed this package */
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 310ad53..bf5a8f6 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2604,7 +2604,6 @@
if (pkg.volumeUuid != null) {
serializer.attribute(null, "volumeUuid", pkg.volumeUuid);
}
-
if (pkg.parentPackageName != null) {
serializer.attribute(null, "parentPackageName", pkg.parentPackageName);
}
@@ -4171,9 +4170,19 @@
};
static final Object[] PRIVATE_FLAG_DUMP_SPEC = new Object[] {
- ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, "PRIVILEGED",
- ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK, "FORWARD_LOCK",
+ ApplicationInfo.PRIVATE_FLAG_HIDDEN, "HIDDEN",
ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
+ ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK, "FORWARD_LOCK",
+ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, "PRIVILEGED",
+ ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS, "HAS_DOMAIN_URLS",
+ ApplicationInfo.PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED, "FORCE_DEVICE_ENCRYPTED",
+ ApplicationInfo.PRIVATE_FLAG_ENCRYPTION_AWARE, "ENCRYPTION_AWARE",
+ ApplicationInfo.PRIVATE_FLAG_AUTOPLAY, "AUTOPLAY",
+ ApplicationInfo.PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE, "PARTIALLY_ENCRYPTION_AWARE",
+ ApplicationInfo.PRIVATE_FLAG_EPHEMERAL, "EPHEMERAL",
+ ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, "REQUIRED_FOR_SYSTEM_USER",
+ ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES, "RESIZEABLE_ACTIVITIES",
+ ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND, "BACKUP_IN_FOREGROUND",
};
void dumpVersionLPr(IndentingPrintWriter pw) {
@@ -4316,6 +4325,10 @@
}
pw.print(prefix); pw.print(" versionName="); pw.println(ps.pkg.mVersionName);
pw.print(prefix); pw.print(" splits="); dumpSplitNames(pw, ps.pkg); pw.println();
+ final int apkSigningVersion = PackageParser.getApkSigningVersion(ps.pkg);
+ if (apkSigningVersion != PackageParser.APK_SIGNING_UNKNOWN) {
+ pw.print(prefix); pw.print(" apkSigningVersion="); pw.println(apkSigningVersion);
+ }
pw.print(prefix); pw.print(" applicationInfo=");
pw.println(ps.pkg.applicationInfo.toString());
pw.print(prefix); pw.print(" flags="); printFlags(pw, ps.pkg.applicationInfo.flags,
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 6320413..252dda7 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -535,6 +535,7 @@
boolean mForceStatusBar;
boolean mForceStatusBarFromKeyguard;
private boolean mForceStatusBarTransparent;
+ boolean mForceNavBarOpaque;
boolean mHideLockScreen;
boolean mForcingShowNavBar;
int mForcingShowNavBarLayer;
@@ -1715,6 +1716,9 @@
if (mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
mShortPressWindowBehavior = SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE;
}
+
+ mForceNavBarOpaque = res.getBoolean(
+ com.android.internal.R.bool.config_forceNavBarAlwaysOpaque);
}
@Override
@@ -7080,6 +7084,10 @@
| View.SYSTEM_UI_TRANSPARENT);
}
+ if (mForceNavBarOpaque) {
+ vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
+ }
+
if (mForceWindowDrawsStatusBarBackground) {
vis |= View.STATUS_BAR_TRANSPARENT;
vis &= ~View.STATUS_BAR_TRANSLUCENT;
diff --git a/services/core/java/com/android/server/policy/ShortcutManager.java b/services/core/java/com/android/server/policy/ShortcutManager.java
index 9284442..57ae523 100644
--- a/services/core/java/com/android/server/policy/ShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ShortcutManager.java
@@ -138,14 +138,16 @@
ComponentName componentName = new ComponentName(packageName, className);
try {
info = packageManager.getActivityInfo(componentName,
- PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES);
} catch (PackageManager.NameNotFoundException e) {
String[] packages = packageManager.canonicalToCurrentPackageNames(
new String[] { packageName });
componentName = new ComponentName(packages[0], className);
try {
info = packageManager.getActivityInfo(componentName,
- PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES);
} catch (PackageManager.NameNotFoundException e1) {
Log.w(TAG, "Unable to add bookmark: " + packageName
+ "/" + className, e);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index f901f95..6218c4e 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -60,6 +60,7 @@
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ArrayUtils;
import com.android.server.EventLogTags;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
@@ -254,6 +255,9 @@
// True if boot completed occurred. We keep the screen on until this happens.
private boolean mBootCompleted;
+ // Runnables that should be triggered on boot completed
+ private Runnable[] mBootCompletedRunnables;
+
// True if auto-suspend mode is enabled.
// Refer to autosuspend.h.
private boolean mHalAutoSuspendModeEnabled;
@@ -525,6 +529,14 @@
userActivityNoUpdateLocked(
now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
updatePowerStateLocked();
+
+ if (!ArrayUtils.isEmpty(mBootCompletedRunnables)) {
+ Slog.d(TAG, "Posting " + mBootCompletedRunnables.length + " delayed runnables");
+ for (Runnable r : mBootCompletedRunnables) {
+ BackgroundThread.getHandler().post(r);
+ }
+ }
+ mBootCompletedRunnables = null;
}
}
}
@@ -750,6 +762,16 @@
mDirty |= DIRTY_SETTINGS;
}
+ private void postAfterBootCompleted(Runnable r) {
+ if (mBootCompleted) {
+ BackgroundThread.getHandler().post(r);
+ } else {
+ Slog.d(TAG, "Delaying runnable until system is booted");
+ mBootCompletedRunnables = ArrayUtils.appendElement(Runnable.class,
+ mBootCompletedRunnables, r);
+ }
+ }
+
void updateLowPowerModeLocked() {
if (mIsPowered && mLowPowerModeSetting) {
if (DEBUG_SPEW) {
@@ -767,7 +789,7 @@
if (mLowPowerModeEnabled != lowPowerModeEnabled) {
mLowPowerModeEnabled = lowPowerModeEnabled;
powerHintInternal(POWER_HINT_LOW_POWER, lowPowerModeEnabled ? 1 : 0);
- BackgroundThread.getHandler().post(new Runnable() {
+ postAfterBootCompleted(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index ba0d340..a0a971a 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -882,6 +882,9 @@
wallpaper = mLockWallpaperMap.get(userId);
if (wallpaper == null) {
// It's already gone; we're done.
+ if (DEBUG) {
+ Slog.i(TAG, "Lock wallpaper already cleared");
+ }
return;
}
} else {
@@ -902,14 +905,19 @@
wallpaper.wallpaperFile.delete();
wallpaper.cropFile.delete();
if (which == FLAG_SET_LOCK) {
+ mLockWallpaperMap.remove(userId);
final IWallpaperManagerCallback cb = mKeyguardListener;
if (cb != null) {
+ if (DEBUG) {
+ Slog.i(TAG, "Notifying keyguard of lock wallpaper clear");
+ }
try {
cb.onWallpaperChanged();
} catch (RemoteException e) {
// Oh well it went away; no big deal
}
}
+ saveSettingsLocked(userId);
return;
}
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index f9e258d..2731f429 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -354,6 +354,11 @@
continue;
}
+ if (DEBUG_ADD_REMOVE) Slog.e(TAG_WM, "win=" + win
+ + " destroySurfaces: mAppStopped=" + mAppStopped
+ + " win.mWindowRemovalAllowed=" + win.mWindowRemovalAllowed
+ + " win.mRemoveOnExit=" + win.mRemoveOnExit);
+
win.destroyOrSaveSurface();
if (win.mRemoveOnExit) {
win.mAnimatingExit = false;
@@ -372,14 +377,19 @@
}
}
- // The application has stopped, so destroy any surfaces which were keeping alive
- // in case they were still being used.
- void notifyAppStopped() {
- mAppStopped = true;
- destroySurfaces();
+ /**
+ * If the application has stopped it is okay to destroy any surfaces which were keeping alive
+ * in case they were still being used.
+ */
+ void notifyAppStopped(boolean stopped) {
+ if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: stopped=" + stopped + " " + this);
+ mAppStopped = stopped;
- // Remove any starting window that was added for this app if they are still around.
- mTask.mService.scheduleRemoveStartingWindowLocked(this);
+ if (stopped) {
+ destroySurfaces();
+ // Remove any starting window that was added for this app if they are still around.
+ mTask.mService.scheduleRemoveStartingWindowLocked(this);
+ }
}
/**
@@ -472,7 +482,7 @@
winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) {
WindowState win = allAppWindows.get(winNdx);
if (win.mAppDied) {
- if (DEBUG_WINDOW_MOVEMENT) {
+ if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
Slog.w(TAG, "removeAllDeadWindows: " + win);
}
// Set mDestroying, we don't want any animation or delayed removal here.
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index f0efebe..79d3d84 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -54,7 +54,8 @@
private final AnimateBoundsUser mTarget;
private final Rect mFrom;
private final Rect mTo;
- private final Rect mTmpRect;
+ private final Rect mTmpRect = new Rect();
+ private final Rect mTmpTaskBounds = new Rect();
private final boolean mMoveToFullScreen;
// True if this this animation was cancelled and will be replaced the another animation from
// the same {@link #AnimateBoundsUser} target.
@@ -63,17 +64,40 @@
// {@link #AnimateBoundsUser} target.
private final boolean mReplacement;
+ // Depending on whether we are animating from
+ // a smaller to a larger size
+ private final int mFrozenTaskWidth;
+ private final int mFrozenTaskHeight;
+
BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to,
boolean moveToFullScreen, boolean replacement) {
super();
mTarget = target;
mFrom = from;
mTo = to;
- mTmpRect = new Rect();
mMoveToFullScreen = moveToFullScreen;
mReplacement = replacement;
addUpdateListener(this);
addListener(this);
+
+ // If we are animating from smaller to larger, we want to change the task bounds
+ // to their final size immediately so we can use scaling to make the window
+ // larger. Likewise if we are going from bigger to smaller, we want to wait until
+ // the end so we don't have to upscale from the smaller finished size.
+ if (animatingToLargerSize()) {
+ mFrozenTaskWidth = mTo.width();
+ mFrozenTaskHeight = mTo.height();
+ } else {
+ mFrozenTaskWidth = mFrom.width();
+ mFrozenTaskHeight = mFrom.height();
+ }
+ }
+
+ boolean animatingToLargerSize() {
+ if (mFrom.width() * mFrom.height() > mTo.width() * mTo.height()) {
+ return false;
+ }
+ return true;
}
@Override
@@ -87,7 +111,13 @@
if (DEBUG) Slog.d(TAG, "animateUpdate: mTarget=" + mTarget + " mBounds="
+ mTmpRect + " from=" + mFrom + " mTo=" + mTo + " value=" + value
+ " remains=" + remains);
- if (!mTarget.setSize(mTmpRect)) {
+
+ if (remains != 0) {
+ mTmpTaskBounds.set(mTmpRect.left, mTmpRect.top,
+ mTmpRect.left + mFrozenTaskWidth, mTmpRect.top + mFrozenTaskHeight);
+ }
+
+ if (!mTarget.setPinnedStackSize(mTmpRect, remains != 0 ? mTmpTaskBounds : null)) {
// Whoops, the target doesn't feel like animating anymore. Let's immediately finish
// any further animation.
animation.cancel();
@@ -99,6 +129,10 @@
public void onAnimationStart(Animator animation) {
if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget
+ " mReplacement=" + mReplacement);
+ if (animatingToLargerSize()) {
+ mTarget.setPinnedStackSize(mFrom, mTo);
+ }
+
if (!mReplacement) {
mTarget.onAnimationStart();
}
@@ -108,6 +142,7 @@
public void onAnimationEnd(Animator animation) {
if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget
+ " mMoveToFullScreen=" + mMoveToFullScreen + " mWillReplace=" + mWillReplace);
+
finishAnimation();
if (mMoveToFullScreen && !mWillReplace) {
mTarget.moveToFullscreen();
@@ -159,6 +194,12 @@
* from the hierarchy and is not valid anymore.
*/
boolean setSize(Rect bounds);
+ /**
+ * Behaves as setSize, but freezes the bounds of any tasks in the target at taskBounds,
+ * to allow for more flexibility during resizing. Only
+ * works for the pinned stack at the moment.
+ */
+ boolean setPinnedStackSize(Rect bounds, Rect taskBounds);
void onAnimationStart();
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index c7b5599..f097eb2 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -19,6 +19,7 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
@@ -685,6 +686,10 @@
&& mStack != null && StackId.isTaskResizeableByDockedStack(mStack.mStackId);
}
+ boolean isFloating() {
+ return StackId.tasksAreFloating(mStack.mStackId);
+ }
+
/**
* Whether the task should be treated as if it's docked. Returns true if the task
* is currently in docked workspace, or it's side-by-side to a docked task.
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 07a6514..86327f7 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -111,6 +111,17 @@
private float mMinimizeAmount;
private final int mDockedStackMinimizeThickness;
+ // If this is true, the task will be down or upscaled
+ // to perfectly fit the region it would have been cropped
+ // to.
+ private boolean mForceScaleToCrop = false;
+ // By default, movement animations are applied to all
+ // window movement. If this is true, animations will not
+ // be applied within this stack. This is useful for example
+ // if the windows are moving as the result of a stack animation,
+ // in which case a second window animation would cause jitter.
+ private boolean mFreezeMovementAnimations = false;
+
TaskStack(WindowManagerService service, int stackId) {
mService = service;
mStackId = stackId;
@@ -1128,17 +1139,38 @@
return true;
}
+ public boolean setPinnedStackSize(Rect bounds, Rect tempTaskBounds) {
+ synchronized (mService.mWindowMap) {
+ if (mDisplayContent == null) {
+ return false;
+ }
+ if (mStackId != PINNED_STACK_ID) {
+ Slog.w(TAG_WM, "Attempt to use pinned stack resize animation helper on"
+ + "non pinned stack");
+ return false;
+ }
+ }
+ try {
+ mService.mActivityManager.resizePinnedStack(bounds, tempTaskBounds);
+ } catch (RemoteException e) {
+ // I don't believe you.
+ }
+ return true;
+ }
+
@Override // AnimatesBounds
public void onAnimationStart() {
synchronized (mService.mWindowMap) {
- setDragResizingLocked(true);
+ mFreezeMovementAnimations = true;
+ mForceScaleToCrop = true;
}
}
@Override // AnimatesBounds
public void onAnimationEnd() {
synchronized (mService.mWindowMap) {
- setDragResizingLocked(false);
+ mFreezeMovementAnimations = false;
+ mForceScaleToCrop = false;
mService.requestTraversal();
}
if (mStackId == PINNED_STACK_ID) {
@@ -1163,4 +1195,12 @@
public void getFullScreenBounds(Rect bounds) {
getDisplayContent().getContentRect(bounds);
}
+
+ public boolean getFreezeMovementAnimations() {
+ return mFreezeMovementAnimations;
+ }
+
+ public boolean getForceScaleToCrop() {
+ return mForceScaleToCrop;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index fe215d5..b64aaa8 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2147,12 +2147,15 @@
void removeWindowLocked(WindowState win) {
win.mWindowRemovalAllowed = true;
+ if (DEBUG_ADD_REMOVE) Slog.v(TAG,
+ "removeWindowLocked: " + win + " callers=" + Debug.getCallers(4));
+
final boolean startingWindow = win.mAttrs.type == TYPE_APPLICATION_STARTING;
if (startingWindow) {
if (DEBUG_STARTING_WINDOW) Slog.d(TAG_WM, "Starting window removed " + win);
}
- if (localLOGV || DEBUG_FOCUS || DEBUG_FOCUS_LIGHT && win==mCurrentFocus) Slog.v(
+ if (localLOGV || DEBUG_FOCUS || DEBUG_FOCUS_LIGHT && win == mCurrentFocus) Slog.v(
TAG_WM, "Remove " + win + " client="
+ Integer.toHexString(System.identityHashCode(win.mClient.asBinder()))
+ ", surfaceController=" + win.mWinAnimator.mSurfaceController + " Callers="
@@ -4194,7 +4197,7 @@
}
@Override
- public void notifyAppStopped(IBinder token) {
+ public void notifyAppStopped(IBinder token, boolean stopped) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"notifyAppStopped()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -4207,7 +4210,7 @@
Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " + token);
return;
}
- wtoken.notifyAppStopped();
+ wtoken.notifyAppStopped(stopped);
}
}
@@ -4244,6 +4247,8 @@
wtoken.appDied = false;
wtoken.removeAllWindows();
} else if (visible) {
+ if (DEBUG_ADD_REMOVE) Slog.v(
+ TAG_WM, "No longer Stopped: " + wtoken);
wtoken.mAppStopped = false;
wtoken.setWindowsExiting(false);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 40b6b50..4ad021e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -184,6 +184,10 @@
private Configuration mConfiguration = Configuration.EMPTY;
private Configuration mOverrideConfig = Configuration.EMPTY;
+ // Represents the changes from our override configuration applied
+ // to the global configuration. This is the only form of configuration
+ // which is suitable for delivery to the client.
+ private Configuration mMergedConfiguration = new Configuration();
// Sticky answer to isConfigChanged(), remains true until new Configuration is assigned.
// Used only on {@link #TYPE_KEYGUARD}.
private boolean mConfigHasChanged;
@@ -434,9 +438,9 @@
// If not null, the window that will be used to replace the old one. This is being set when
// the window is added and unset when this window reports its first draw.
WindowState mReplacingWindow = null;
-
// Whether this window is being moved via the resize API
boolean mMovedByResize;
+
/**
* Wake lock for drawing.
* Even though it's slightly more expensive to do so, we will use a separate wake lock
@@ -635,7 +639,7 @@
final Task task = getTask();
final boolean fullscreenTask = task == null || task.isFullscreen();
- final boolean freeformWorkspace = task != null && task.inFreeformWorkspace();
+ final boolean windowsAreFloating = task != null && task.isFloating();
if (fullscreenTask || (isChildWindow()
&& (mAttrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) != 0)) {
@@ -661,10 +665,10 @@
mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
}
- if (freeformWorkspace) {
- // In free form mode we have only to set the rectangle if it wasn't set already. No
- // need to intersect it with the (visible) "content frame" since it is allowed to
- // be outside the visible desktop.
+ if (windowsAreFloating) {
+ // In floating modes (e.g. freeform, pinned) we have only to set the rectangle
+ // if it wasn't set already. No need to intersect it with the (visible)
+ // "content frame" since it is allowed to be outside the visible desktop.
if (mContainingFrame.isEmpty()) {
mContainingFrame.set(cf);
}
@@ -720,7 +724,7 @@
// Make sure the content and visible frames are inside of the
// final window frame.
- if (freeformWorkspace && !mFrame.isEmpty()) {
+ if (windowsAreFloating && !mFrame.isEmpty()) {
// Keep the frame out of the blocked system area, limit it in size to the content area
// and make sure that there is always a minimum visible so that the user can drag it
// into a usable area..
@@ -772,9 +776,9 @@
Math.min(mStableFrame.bottom, frame.bottom));
}
- if (!inFreeformWorkspace()) {
- // Freeform windows can be positioned outside of the display frame, but that is not a
- // reason to provide them with overscan insets.
+ if (!windowsAreFloating) {
+ // Windows from floating tasks (e.g. freeform, pinned) may be positioned outside
+ // of the display frame, but that is not a reason to provide them with overscan insets.
mOverscanInsets.set(Math.max(mOverscanFrame.left - frame.left, 0),
Math.max(mOverscanFrame.top - frame.top, 0),
Math.max(frame.right - mOverscanFrame.right, 0),
@@ -1355,6 +1359,11 @@
mConfiguration = newConfig;
mOverrideConfig = newOverrideConfig;
mConfigHasChanged = false;
+
+ mMergedConfiguration.setTo(newConfig);
+ if (newOverrideConfig != null && newOverrideConfig != Configuration.EMPTY) {
+ mMergedConfiguration.updateFrom(newOverrideConfig);
+ }
}
void setHasSurface(boolean hasSurface) {
@@ -1616,9 +1625,10 @@
mTurnOnScreen = true;
}
if (isConfigChanged()) {
+ final Configuration newConfig = updateConfiguration();
if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + this + " visible with new config: "
- + mService.mCurConfiguration);
- outConfig.setTo(mService.mCurConfiguration);
+ + newConfig);
+ outConfig.setTo(newConfig);
}
}
@@ -1902,6 +1912,12 @@
mWinAnimator.hide("saved surface");
mWinAnimator.mDrawState = WindowStateAnimator.NO_SURFACE;
setHasSurface(false);
+ // The client should have disconnected at this point, but if it doesn't,
+ // we need to make sure it's disconnected. Otherwise when we reuse the surface
+ // the client can't reconnect to the buffer queue, and rendering will fail.
+ if (mWinAnimator.mSurfaceController != null) {
+ mWinAnimator.mSurfaceController.disconnectInTransaction();
+ }
} else {
mWinAnimator.destroySurfaceLocked();
}
@@ -2055,21 +2071,30 @@
}
}
+ /**
+ * Update our current configurations, based on task configuration.
+ *
+ * @return A configuration suitable for sending to the client.
+ */
+ private Configuration updateConfiguration() {
+ final Task task = getTask();
+ final Configuration overrideConfig =
+ (task != null) ? task.mOverrideConfig : Configuration.EMPTY;
+ final boolean configChanged = isConfigChanged();
+ if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) && configChanged) {
+ Slog.i(TAG, "Sending new config to window " + this + ": " +
+ " / config=" + mService.mCurConfiguration + " overrideConfig=" + overrideConfig);
+ }
+ setConfiguration(mService.mCurConfiguration, overrideConfig);
+ return mMergedConfiguration;
+ }
+
void reportResized() {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.reportResized_" + getWindowTag());
try {
if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
+ ": " + mCompatFrame);
- final boolean configChanged = isConfigChanged();
- final Task task = getTask();
- final Configuration overrideConfig =
- (task != null) ? task.mOverrideConfig : Configuration.EMPTY;
- if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) && configChanged) {
- Slog.i(TAG, "Sending new config to window " + this + ": "
- + " / config="
- + mService.mCurConfiguration + " overrideConfig=" + overrideConfig);
- }
- setConfiguration(mService.mCurConfiguration, overrideConfig);
+ final Configuration newConfig = isConfigChanged() ? updateConfiguration() : null;
if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING)
Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");
@@ -2080,7 +2105,6 @@
final Rect stableInsets = mLastStableInsets;
final Rect outsets = mLastOutsets;
final boolean reportDraw = mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING;
- final Configuration newConfig = configChanged ? mConfiguration : null;
if (mAttrs.type != WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
&& mClient instanceof IWindow.Stub) {
// To prevent deadlock simulate one-way call if win.mClient is a local object.
@@ -2479,7 +2503,8 @@
final int ph = mContainingFrame.height();
final Task task = getTask();
final boolean nonFullscreenTask = task != null && !task.isFullscreen();
-
+ final boolean fitToDisplay = task != null &&
+ !task.isFloating();
float x, y;
int w,h;
@@ -2536,7 +2561,17 @@
(int) (y + mAttrs.verticalMargin * ph), mFrame);
// Now make sure the window fits in the overall display frame.
- Gravity.applyDisplay(mAttrs.gravity, mDisplayFrame, mFrame);
+ if (fitToDisplay) {
+ Gravity.applyDisplay(mAttrs.gravity, mDisplayFrame, mFrame);
+ }
+
+ // We need to make sure we update the CompatFrame as it is used for
+ // cropping decisions, etc, on systems where we lack a decor layer.
+ mCompatFrame.set(mFrame);
+ if (mEnforceSizeCompat) {
+ // See comparable block in computeFrameLw.
+ mCompatFrame.scale(mInvGlobalScale);
+ }
}
boolean isChildWindow() {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 02f9aa1..c1ff96e 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -20,6 +20,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
@@ -467,9 +468,8 @@
return;
}
- if (WindowManagerService.localLOGV) Slog.v(
- TAG, "Exit animation finished in " + this
- + ": remove=" + mWin.mRemoveOnExit);
+ if (WindowManagerService.localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG,
+ "Exit animation finished in " + this + ": remove=" + mWin.mRemoveOnExit);
mWin.mDestroying = true;
@@ -1115,11 +1115,11 @@
}
}
- void updateSurfaceWindowCrop(final boolean recoveringMemory) {
+ Rect calculateSurfaceWindowCrop() {
final WindowState w = mWin;
final DisplayContent displayContent = w.getDisplayContent();
if (displayContent == null) {
- return;
+ return null;
}
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Updating crop for window: " + w + ", " + "mLastCrop=" +
@@ -1187,7 +1187,7 @@
clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top);
adjustCropToStackBounds(w, clipRect, isFreeformResizing);
- if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Clip rect after stack adjustment=" + mClipRect);
+ if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Clip rect after stack adjustment=" + clipRect);
w.transformFromScreenToSurfaceSpace(clipRect);
@@ -1196,6 +1196,10 @@
clipRect.setEmpty();
}
+ return clipRect;
+ }
+
+ void updateSurfaceWindowCrop(Rect clipRect, boolean recoveringMemory) {
if (!clipRect.equals(mLastClipRect)) {
mLastClipRect.set(clipRect);
mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
@@ -1237,6 +1241,7 @@
w.mFrame.left + mWin.mXOffset - w.getAttrs().surfaceInsets.left;
final int frameY = isFreeformResizing ? (int) mSurfaceController.getY() :
w.mFrame.top + mWin.mYOffset - w.getAttrs().surfaceInsets.top;
+
// We need to do some acrobatics with surface position, because their clip region is
// relative to the inside of the surface, but the stack bounds aren't.
clipRect.left = Math.max(0,
@@ -1251,14 +1256,44 @@
void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
final WindowState w = mWin;
+ final Task task = w.getTask();
mTmpSize.set(w.mShownPosition.x, w.mShownPosition.y, 0, 0);
calculateSurfaceBounds(w, w.getAttrs());
- mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top, recoveringMemory);
+ float extraHScale = (float) 1.0;
+ float extraVScale = (float) 1.0;
- mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale, mDtDx * w.mVScale,
- mDsDy * w.mHScale, mDtDy * w.mVScale, recoveringMemory);
+ final Rect crop = calculateSurfaceWindowCrop();
+ if (task != null && task.mStack.getForceScaleToCrop()) {
+ extraHScale = crop.width() / (float)mTmpSize.width();
+ extraVScale = crop.height() / (float)mTmpSize.height();
+
+ // In the case of ForceScaleToCrop we scale entire tasks together,
+ // and so we need to scale our offsets relative to the task bounds
+ // or parent and child windows would fall out of alignment.
+ int posX = (int) (mTmpSize.left - w.mAttrs.x * (1 - extraHScale));
+ int posY = (int) (mTmpSize.top - w.mAttrs.y * (1 - extraVScale));
+ posX += w.getAttrs().surfaceInsets.left * (1 - extraHScale);
+ posY += w.getAttrs().surfaceInsets.top * (1 - extraVScale);
+ mSurfaceController.setPositionInTransaction(posX, posY, recoveringMemory);
+
+ // Since we are scaled to fit in our previously desired crop, we can now
+ // expose the whole window in buffer space, and not risk extending
+ // past where the system would have cropped us
+ crop.set(0, 0, mTmpSize.width(), mTmpSize.height());
+ updateSurfaceWindowCrop(crop, recoveringMemory);
+ } else {
+ mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
+ recoveringMemory);
+ updateSurfaceWindowCrop(crop, recoveringMemory);
+ }
+
+
+ mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * extraHScale,
+ mDtDx * w.mVScale * extraVScale,
+ mDsDy * w.mHScale * extraHScale,
+ mDtDy * w.mVScale * extraVScale, recoveringMemory);
mSurfaceResized = mSurfaceController.setSizeInTransaction(
mTmpSize.width(), mTmpSize.height(),
recoveringMemory);
@@ -1270,7 +1305,6 @@
w.applyDimLayerIfNeeded();
}
- updateSurfaceWindowCrop(recoveringMemory);
}
void prepareSurfaceLocked(final boolean recoveringMemory) {
@@ -1409,7 +1443,7 @@
SurfaceControl.openTransaction();
mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left,
mWin.mFrame.top + top, false);
- updateSurfaceWindowCrop(false);
+ updateSurfaceWindowCrop(calculateSurfaceWindowCrop(), false);
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + mWin
+ " pos=(" + left + "," + top + ")", e);
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 2972a24..fb07512 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -138,7 +138,7 @@
void destroyInTransaction() {
// if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
- Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(4));
+ Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(8));
// }
try {
if (mSurfaceControl != null) {
@@ -152,6 +152,20 @@
}
}
+ void disconnectInTransaction() {
+ if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+ Slog.i(TAG, "Disconnecting client: " + this);
+ }
+
+ try {
+ if (mSurfaceControl != null) {
+ mSurfaceControl.disconnect();
+ }
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Error disconnecting surface in: " + this, e);
+ }
+ }
+
void setCropInTransaction(Rect clipRect, boolean recoveringMemory) {
if (SHOW_TRANSACTIONS) logSurface(
"CROP " + clipRect.toShortString(), null);
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 856d30a..e3955fe 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -651,6 +651,7 @@
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState w = windows.get(i);
+ final Task task = w.getTask();
final boolean obscuredChanged = w.mObscured != mObscured;
// Update effect.
@@ -683,7 +684,8 @@
final boolean adjustedForMinimizedDockedStack = w.getTask() != null &&
w.getTask().mStack.isAdjustedForMinimizedDockedStack();
if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
- && !w.isDragResizing() && !adjustedForMinimizedDockedStack) {
+ && !w.isDragResizing() && !adjustedForMinimizedDockedStack
+ && (task == null || !w.getTask().mStack.getFreezeMovementAnimations())) {
winAnimator.setMoveAnimation(left, top);
}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index c97323c..aa14fff 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -140,7 +140,7 @@
ALOGD("Unknown constellation type with Svid = %d.", info.svid);
info.constellation = GNSS_CONSTELLATION_UNKNOWN;
}
- info.snr = sv_status->sv_list[i].snr;
+ info.c_n0_dbhz = sv_status->sv_list[i].snr;
info.elevation = sv_status->sv_list[i].elevation;
info.azimuth = sv_status->sv_list[i].azimuth;
info.flags = GNSS_SV_FLAGS_NONE;
@@ -698,12 +698,12 @@
}
static jint android_location_GnssLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
- jintArray svidWithFlagArray, jfloatArray snrArray, jfloatArray elevArray,
+ jintArray svidWithFlagArray, jfloatArray cn0Array, jfloatArray elevArray,
jfloatArray azumArray)
{
// this should only be called from within a call to reportSvStatus
jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
- jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
+ jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0);
jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
@@ -713,13 +713,13 @@
svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
(info.constellation << CONSTELLATION_TYPE_SHIFT_WIDTH) |
info.flags;
- snrs[i] = info.snr;
+ cn0s[i] = info.c_n0_dbhz;
elev[i] = info.elevation;
azim[i] = info.azimuth;
}
env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
- env->ReleaseFloatArrayElements(snrArray, snrs, 0);
+ env->ReleaseFloatArrayElements(cn0Array, cn0s, 0);
env->ReleaseFloatArrayElements(elevArray, elev, 0);
env->ReleaseFloatArrayElements(azumArray, azim, 0);
return (jint) sGnssSvListSize;
@@ -1095,7 +1095,9 @@
JavaObject object(env, "android/location/GnssClock");
GpsClockFlags flags = clock->flags;
- SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
+ SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND,
+ LeapSecond,
+ static_cast<int32_t>(clock->leap_second));
// GnssClock only supports the more effective HW_CLOCK type, so type
// handling and documentation complexity has been removed. To convert the
@@ -1122,18 +1124,18 @@
break;
}
- SET(TimeInNs, clock->time_ns);
+ SET(TimeNanos, clock->time_ns);
SET_IF(GNSS_CLOCK_HAS_TIME_UNCERTAINTY,
- TimeUncertaintyInNs,
+ TimeUncertaintyNanos,
clock->time_uncertainty_ns);
- SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasInNs, clock->full_bias_ns);
- SET_IF(GNSS_CLOCK_HAS_BIAS, BiasInNs, clock->bias_ns);
+ SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasNanos, clock->full_bias_ns);
+ SET_IF(GNSS_CLOCK_HAS_BIAS, BiasNanos, clock->bias_ns);
SET_IF(GNSS_CLOCK_HAS_BIAS_UNCERTAINTY,
- BiasUncertaintyInNs,
+ BiasUncertaintyNanos,
clock->bias_uncertainty_ns);
- SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftInNsPerSec, clock->drift_nsps);
+ SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftNanosPerSecond, clock->drift_nsps);
SET_IF(GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY,
- DriftUncertaintyInNsPerSec,
+ DriftUncertaintyNanosPerSecond,
clock->drift_uncertainty_nsps);
return object.get();
@@ -1143,20 +1145,21 @@
JavaObject object(env, "android/location/GnssClock");
GpsClockFlags flags = clock->flags;
- SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
- SET(Type, static_cast<uint8_t>(GPS_CLOCK_TYPE_LOCAL_HW_TIME));
- SET(TimeInNs, clock->time_ns);
+ SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND,
+ LeapSecond,
+ static_cast<int32_t>(clock->leap_second));
+ SET(TimeNanos, clock->time_ns);
SET_IF(GNSS_CLOCK_HAS_TIME_UNCERTAINTY,
- TimeUncertaintyInNs,
+ TimeUncertaintyNanos,
clock->time_uncertainty_ns);
- SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasInNs, clock->full_bias_ns);
- SET_IF(GNSS_CLOCK_HAS_BIAS, BiasInNs, clock->bias_ns);
+ SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasNanos, clock->full_bias_ns);
+ SET_IF(GNSS_CLOCK_HAS_BIAS, BiasNanos, clock->bias_ns);
SET_IF(GNSS_CLOCK_HAS_BIAS_UNCERTAINTY,
- BiasUncertaintyInNs,
+ BiasUncertaintyNanos,
clock->bias_uncertainty_ns);
- SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftInNsPerSec, clock->drift_nsps);
+ SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftNanosPerSecond, clock->drift_nsps);
SET_IF(GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY,
- DriftUncertaintyInNsPerSec,
+ DriftUncertaintyNanosPerSecond,
clock->drift_uncertainty_nsps);
SET(HardwareClockDiscontinuityCount, clock->hw_clock_discontinuity_count);
@@ -1168,41 +1171,30 @@
GpsMeasurement* measurement) {
JavaObject object(env, "android/location/GnssMeasurement");
GpsMeasurementFlags flags = measurement->flags;
- SET(Svid, static_cast<int16_t>(measurement->prn));
+ SET(Svid, static_cast<int32_t>(measurement->prn));
if (measurement->prn >= 1 || measurement->prn <= 32) {
- SET(ConstellationType, static_cast<uint8_t>(GNSS_CONSTELLATION_GPS));
+ SET(ConstellationType, static_cast<int32_t>(GNSS_CONSTELLATION_GPS));
} else {
ALOGD("Unknown constellation type with Svid = %d.", measurement->prn);
SET(ConstellationType,
- static_cast<uint8_t>(GNSS_CONSTELLATION_UNKNOWN));
+ static_cast<int32_t>(GNSS_CONSTELLATION_UNKNOWN));
}
- SET(TimeOffsetInNs, measurement->time_offset_ns);
- SET(State, measurement->state);
- SET(ReceivedSvTimeInNs, measurement->received_gps_tow_ns);
- SET(ReceivedSvTimeUncertaintyInNs,
+ SET(TimeOffsetNanos, measurement->time_offset_ns);
+ SET(State, static_cast<int32_t>(measurement->state));
+ SET(ReceivedSvTimeNanos, measurement->received_gps_tow_ns);
+ SET(ReceivedSvTimeUncertaintyNanos,
measurement->received_gps_tow_uncertainty_ns);
- SET(Cn0InDbHz, measurement->c_n0_dbhz);
- SET(PseudorangeRateInMetersPerSec, measurement->pseudorange_rate_mps);
- SET(PseudorangeRateUncertaintyInMetersPerSec,
+ SET(Cn0DbHz, measurement->c_n0_dbhz);
+ SET(PseudorangeRateMetersPerSecond, measurement->pseudorange_rate_mps);
+ SET(PseudorangeRateUncertaintyMetersPerSecond,
measurement->pseudorange_rate_uncertainty_mps);
- SET(AccumulatedDeltaRangeState, measurement->accumulated_delta_range_state);
- SET(AccumulatedDeltaRangeInMeters, measurement->accumulated_delta_range_m);
- SET(AccumulatedDeltaRangeUncertaintyInMeters,
+ SET(AccumulatedDeltaRangeState,
+ static_cast<int32_t>(measurement->accumulated_delta_range_state));
+ SET(AccumulatedDeltaRangeMeters, measurement->accumulated_delta_range_m);
+ SET(AccumulatedDeltaRangeUncertaintyMeters,
measurement->accumulated_delta_range_uncertainty_m);
- SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE,
- PseudorangeInMeters,
- measurement->pseudorange_m);
- SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY,
- PseudorangeUncertaintyInMeters,
- measurement->pseudorange_uncertainty_m);
- SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE,
- CodePhaseInChips,
- measurement->code_phase_chips);
- SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY,
- CodePhaseUncertaintyInChips,
- measurement->code_phase_uncertainty_chips);
SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
- CarrierFrequencyInHz,
+ CarrierFrequencyHz,
measurement->carrier_frequency_hz);
SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_CYCLES,
CarrierCycles,
@@ -1213,33 +1205,8 @@
SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
CarrierPhaseUncertainty,
measurement->carrier_phase_uncertainty);
- SET(LossOfLock, measurement->loss_of_lock);
- SET_IF(GNSS_MEASUREMENT_HAS_BIT_NUMBER, BitNumber, measurement->bit_number);
- SET_IF(GNSS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT,
- TimeFromLastBitInMs,
- measurement->time_from_last_bit_ms);
- SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT,
- DopplerShiftInHz,
- measurement->doppler_shift_hz);
- SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY,
- DopplerShiftUncertaintyInHz,
- measurement->doppler_shift_uncertainty_hz);
SET(MultipathIndicator, measurement->multipath_indicator);
SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
- SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION,
- ElevationInDeg,
- measurement->elevation_deg);
- SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY,
- ElevationUncertaintyInDeg,
- measurement->elevation_uncertainty_deg);
- SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH,
- AzimuthInDeg,
- measurement->azimuth_deg);
- SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY,
- AzimuthUncertaintyInDeg,
- measurement->azimuth_uncertainty_deg);
- SET(UsedInFix,
- (flags & GNSS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
return object.get();
}
@@ -1250,34 +1217,23 @@
GpsMeasurementFlags flags = measurement->flags;
SET(Svid, measurement->svid);
- SET(ConstellationType, measurement->constellation);
- SET(TimeOffsetInNs, measurement->time_offset_ns);
- SET(State, measurement->state);
- SET(ReceivedSvTimeInNs, measurement->received_sv_time_in_ns);
- SET(ReceivedSvTimeUncertaintyInNs,
+ SET(ConstellationType, static_cast<int32_t>(measurement->constellation));
+ SET(TimeOffsetNanos, measurement->time_offset_ns);
+ SET(State, static_cast<int32_t>(measurement->state));
+ SET(ReceivedSvTimeNanos, measurement->received_sv_time_in_ns);
+ SET(ReceivedSvTimeUncertaintyNanos,
measurement->received_sv_time_uncertainty_in_ns);
- SET(Cn0InDbHz, measurement->c_n0_dbhz);
- SET(PseudorangeRateInMetersPerSec, measurement->pseudorange_rate_mps);
- SET(PseudorangeRateUncertaintyInMetersPerSec,
+ SET(Cn0DbHz, measurement->c_n0_dbhz);
+ SET(PseudorangeRateMetersPerSecond, measurement->pseudorange_rate_mps);
+ SET(PseudorangeRateUncertaintyMetersPerSecond,
measurement->pseudorange_rate_uncertainty_mps);
- SET(AccumulatedDeltaRangeState, measurement->accumulated_delta_range_state);
- SET(AccumulatedDeltaRangeInMeters, measurement->accumulated_delta_range_m);
- SET(AccumulatedDeltaRangeUncertaintyInMeters,
+ SET(AccumulatedDeltaRangeState,
+ static_cast<int32_t>(measurement->accumulated_delta_range_state));
+ SET(AccumulatedDeltaRangeMeters, measurement->accumulated_delta_range_m);
+ SET(AccumulatedDeltaRangeUncertaintyMeters,
measurement->accumulated_delta_range_uncertainty_m);
- SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE,
- PseudorangeInMeters,
- measurement->pseudorange_m);
- SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY,
- PseudorangeUncertaintyInMeters,
- measurement->pseudorange_uncertainty_m);
- SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE,
- CodePhaseInChips,
- measurement->code_phase_chips);
- SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY,
- CodePhaseUncertaintyInChips,
- measurement->code_phase_uncertainty_chips);
SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
- CarrierFrequencyInHz,
+ CarrierFrequencyHz,
measurement->carrier_frequency_hz);
SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_CYCLES,
CarrierCycles,
@@ -1288,32 +1244,8 @@
SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
CarrierPhaseUncertainty,
measurement->carrier_phase_uncertainty);
- SET_IF(GNSS_MEASUREMENT_HAS_BIT_NUMBER, BitNumber, measurement->bit_number);
- SET_IF(GNSS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT,
- TimeFromLastBitInMs,
- measurement->time_from_last_bit_ms);
- SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT,
- DopplerShiftInHz,
- measurement->doppler_shift_hz);
- SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY,
- DopplerShiftUncertaintyInHz,
- measurement->doppler_shift_uncertainty_hz);
SET(MultipathIndicator, measurement->multipath_indicator);
SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
- SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION,
- ElevationInDeg,
- measurement->elevation_deg);
- SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY,
- ElevationUncertaintyInDeg,
- measurement->elevation_uncertainty_deg);
- SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH,
- AzimuthInDeg,
- measurement->azimuth_deg);
- SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY,
- AzimuthUncertaintyInDeg,
- measurement->azimuth_uncertainty_deg);
- SET(UsedInFix,
- (flags & GNSS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
return object.get();
}
@@ -1493,21 +1425,22 @@
return NULL;
}
JavaObject object(env, "android/location/GnssNavigationMessage");
- SET(Svid, static_cast<int16_t>(message->prn));
+ SET(Svid, static_cast<int32_t>(message->prn));
if (message->prn >=1 && message->prn <= 32) {
- SET(ConstellationType, static_cast<uint8_t>(GNSS_CONSTELLATION_GPS));
+ SET(ConstellationType, static_cast<int32_t>(GNSS_CONSTELLATION_GPS));
// Legacy driver doesn't set the higher byte to constellation type
// correctly. Set the higher byte to 'GPS'.
- SET(Type, static_cast<int16_t>(message->type | 0x0100));
+ SET(Type, static_cast<int32_t>(message->type | 0x0100));
} else {
ALOGD("Unknown constellation type with Svid = %d.", message->prn);
SET(ConstellationType,
- static_cast<uint8_t>(GNSS_CONSTELLATION_UNKNOWN));
- SET(Type, static_cast<int16_t>(GNSS_NAVIGATION_MESSAGE_TYPE_UNKNOWN));
+ static_cast<int32_t>(GNSS_CONSTELLATION_UNKNOWN));
+ SET(Type, static_cast<int32_t>(GNSS_NAVIGATION_MESSAGE_TYPE_UNKNOWN));
}
- SET(MessageId, message->message_id);
- SET(SubmessageId, message->submessage_id);
+ SET(MessageId, static_cast<int32_t>(message->message_id));
+ SET(SubmessageId, static_cast<int32_t>(message->submessage_id));
object.callSetter("setData", data, dataLength);
+ SET(Status, static_cast<int32_t>(message->status));
return object.get();
}
@@ -1520,11 +1453,12 @@
return NULL;
}
JavaObject object(env, "android/location/GnssNavigationMessage");
- SET(Type, message->type);
- SET(Svid, message->svid);
- SET(MessageId, message->message_id);
- SET(SubmessageId, message->submessage_id);
+ SET(Type, static_cast<int32_t>(message->type));
+ SET(Svid, static_cast<int32_t>(message->svid));
+ SET(MessageId, static_cast<int32_t>(message->message_id));
+ SET(SubmessageId, static_cast<int32_t>(message->submessage_id));
object.callSetter("setData", data, dataLength);
+ SET(Status, static_cast<int32_t>(message->status));
return object.get();
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 0252ea4..d8aa5d7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -31,8 +31,8 @@
import android.Manifest.permission;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accounts.AccountManager;
+import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
@@ -151,6 +151,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
@@ -280,6 +282,20 @@
private static final int PROFILE_KEYGUARD_FEATURES =
PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER | PROFILE_KEYGUARD_FEATURES_PROFILE_ONLY;
+ private static final int CODE_OK = 0;
+ private static final int CODE_HAS_DEVICE_OWNER = 1;
+ private static final int CODE_USER_HAS_PROFILE_OWNER = 2;
+ private static final int CODE_USER_NOT_RUNNING = 3;
+ private static final int CODE_USER_SETUP_COMPLETED = 4;
+ private static final int CODE_NONSYSTEM_USER_EXISTS = 5;
+ private static final int CODE_ACCOUNTS_NOT_EMPTY = 6;
+ private static final int CODE_NOT_SYSTEM_USER = 7;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({ CODE_OK, CODE_HAS_DEVICE_OWNER, CODE_USER_HAS_PROFILE_OWNER, CODE_USER_NOT_RUNNING,
+ CODE_USER_SETUP_COMPLETED, CODE_NOT_SYSTEM_USER })
+ private @interface DeviceOwnerPreConditionCode {}
+
private static final int DEVICE_ADMIN_DEACTIVATE_TIMEOUT = 10000;
final Context mContext;
@@ -308,7 +324,7 @@
* Whether or not device admin feature is supported. If it isn't return defaults for all
* public methods.
*/
- private boolean mHasFeature;
+ boolean mHasFeature;
private final SecurityLogMonitor mSecurityLogMonitor;
@@ -328,7 +344,7 @@
@Override
public void onReceive(Context context, Intent intent) {
- if (RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_DISPATCH.equals(intent.getAction())
+ if (DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH.equals(intent.getAction())
&& mRemoteBugreportServiceIsActive.get()) {
onBugreportFinished(intent);
}
@@ -342,10 +358,9 @@
String action = intent.getAction();
mInjector.getNotificationManager().cancel(LOG_TAG,
RemoteBugreportUtils.NOTIFICATION_ID);
- if (RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
+ if (DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
onBugreportSharingAccepted();
- } else if (RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_DECLINED
- .equals(action)) {
+ } else if (DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED.equals(action)) {
onBugreportSharingDeclined();
}
mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
@@ -437,15 +452,14 @@
&& userHandle == mOwners.getDeviceOwnerUserId()
&& getDeviceOwnerRemoteBugreportUri() != null) {
IntentFilter filterConsent = new IntentFilter();
- filterConsent.addAction(
- RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_DECLINED);
- filterConsent.addAction(
- RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED);
+ filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED);
+ filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED);
mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
- mInjector.getNotificationManager().notify(LOG_TAG,
+ mInjector.getNotificationManager().notifyAsUser(LOG_TAG,
RemoteBugreportUtils.NOTIFICATION_ID,
RemoteBugreportUtils.buildNotification(mContext,
- RemoteBugreportUtils.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED));
+ DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
+ UserHandle.ALL);
}
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|| ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
@@ -5068,9 +5082,9 @@
mRemoteBugreportServiceIsActive.set(true);
mRemoteBugreportSharingAccepted.set(false);
registerRemoteBugreportReceivers();
- mInjector.getNotificationManager().notify(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
+ mInjector.getNotificationManager().notifyAsUser(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
RemoteBugreportUtils.buildNotification(mContext,
- RemoteBugreportUtils.NOTIFICATION_BUGREPORT_STARTED));
+ DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED), UserHandle.ALL);
mHandler.postDelayed(mRemoteBugreportTimeoutRunnable,
RemoteBugreportUtils.REMOTE_BUGREPORT_TIMEOUT_MILLIS);
return true;
@@ -5104,7 +5118,7 @@
private void registerRemoteBugreportReceivers() {
try {
IntentFilter filterFinished = new IntentFilter(
- RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_DISPATCH,
+ DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH,
RemoteBugreportUtils.BUGREPORT_MIMETYPE);
mContext.registerReceiver(mRemoteBugreportFinishedReceiver, filterFinished);
} catch (IntentFilter.MalformedMimeTypeException e) {
@@ -5112,8 +5126,8 @@
Slog.w(LOG_TAG, "Failed to set type " + RemoteBugreportUtils.BUGREPORT_MIMETYPE, e);
}
IntentFilter filterConsent = new IntentFilter();
- filterConsent.addAction(RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_DECLINED);
- filterConsent.addAction(RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED);
+ filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED);
+ filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED);
mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
}
@@ -5126,16 +5140,17 @@
bugreportUriString = bugreportUri.toString();
}
String bugreportHash = intent.getStringExtra(
- RemoteBugreportUtils.EXTRA_REMOTE_BUGREPORT_HASH);
+ DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH);
if (mRemoteBugreportSharingAccepted.get()) {
shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
mInjector.getNotificationManager().cancel(LOG_TAG,
RemoteBugreportUtils.NOTIFICATION_ID);
} else {
setDeviceOwnerRemoteBugreportUriAndHash(bugreportUriString, bugreportHash);
- mInjector.getNotificationManager().notify(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
+ mInjector.getNotificationManager().notifyAsUser(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
RemoteBugreportUtils.buildNotification(mContext,
- RemoteBugreportUtils.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED));
+ DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
+ UserHandle.ALL);
}
mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
}
@@ -5166,9 +5181,10 @@
if (bugreportUriString != null) {
shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
} else if (mRemoteBugreportServiceIsActive.get()) {
- mInjector.getNotificationManager().notify(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
+ mInjector.getNotificationManager().notifyAsUser(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
RemoteBugreportUtils.buildNotification(mContext,
- RemoteBugreportUtils.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED));
+ DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED),
+ UserHandle.ALL);
}
}
@@ -5530,7 +5546,8 @@
Preconditions.checkNotNull(packageName, "packageName is null");
final int callingUid = mInjector.binderGetCallingUid();
try {
- int uid = mContext.getPackageManager().getPackageUidAsUser(packageName, 0);
+ int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
+ UserHandle.getUserId(callingUid));
if (uid != callingUid) {
throw new SecurityException("Invalid packageName");
}
@@ -5933,52 +5950,40 @@
/**
* The Device owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS
* permission.
- * The device owner can only be set before the setup phase of the primary user has completed,
- * except for adb if no accounts or additional users are present on the device.
*/
private void enforceCanSetDeviceOwnerLocked(int userId) {
- if (mOwners.hasDeviceOwner()) {
- throw new IllegalStateException("Trying to set the device owner, but device owner "
- + "is already set.");
- }
- if (mOwners.hasProfileOwner(userId)) {
- throw new IllegalStateException("Trying to set the device owner, but the user already "
- + "has a profile owner.");
- }
- if (!mUserManager.isUserRunning(new UserHandle(userId))) {
- throw new IllegalStateException("User not running: " + userId);
- }
-
int callingUid = mInjector.binderGetCallingUid();
- if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
- if (!hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
- return;
- }
- // STOPSHIP Do proper check in split user mode
- if (!mInjector.userManagerIsSplitSystemUser()) {
- if (mUserManager.getUserCount() > 1) {
- throw new IllegalStateException(
- "Not allowed to set the device owner because there "
- + "are already several users on the device");
- }
- if (AccountManager.get(mContext).getAccounts().length > 0) {
- throw new IllegalStateException(
- "Not allowed to set the device owner because there "
- + "are already some accounts on the device");
- }
- }
- return;
+ boolean isAdb = callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
+ if (!isAdb) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
}
- // STOPSHIP check the caller UID with userId
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
- // STOPSHIP Do proper check in split user mode
- if (!mInjector.userManagerIsSplitSystemUser()) {
- if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
- throw new IllegalStateException("Cannot set the device owner if the device is "
- + "already set-up");
- }
+ final int code = checkSetDeviceOwnerPreCondition(userId, isAdb);
+ switch (code) {
+ case CODE_OK:
+ return;
+ case CODE_HAS_DEVICE_OWNER:
+ throw new IllegalStateException(
+ "Trying to set the device owner, but device owner is already set.");
+ case CODE_USER_HAS_PROFILE_OWNER:
+ throw new IllegalStateException("Trying to set the device owner, but the user "
+ + "already has a profile owner.");
+ case CODE_USER_NOT_RUNNING:
+ throw new IllegalStateException("User not running: " + userId);
+ case CODE_NOT_SYSTEM_USER:
+ throw new IllegalStateException("User is not system user");
+ case CODE_USER_SETUP_COMPLETED:
+ throw new IllegalStateException(
+ "Cannot set the device owner if the device is already set-up");
+ case CODE_NONSYSTEM_USER_EXISTS:
+ throw new IllegalStateException("Not allowed to set the device owner because there "
+ + "are already several users on the device");
+ case CODE_ACCOUNTS_NOT_EMPTY:
+ throw new IllegalStateException("Not allowed to set the device owner because there "
+ + "are already some accounts on the device");
+ default:
+ throw new IllegalStateException("Unknown @DeviceOwnerPreConditionCode " + code);
}
}
@@ -7809,6 +7814,26 @@
listener.onCrossProfileWidgetProvidersChanged(userId, packages);
}
}
+
+ @Override
+ public boolean hasDeviceOwnerOrProfileOwner(String packageName, int userId) {
+ if (!mHasFeature || packageName == null) {
+ return false;
+ }
+ if (userId < 0) {
+ throw new UnsupportedOperationException("userId should be >= 0");
+ }
+ synchronized (DevicePolicyManagerService.this) {
+ if (packageName.equals(mOwners.getProfileOwnerPackage(userId))) {
+ return true;
+ }
+ if (userId == mOwners.getDeviceOwnerUserId()
+ && packageName.equals(mOwners.getDeviceOwnerPackageName())) {
+ return true;
+ }
+ }
+ return false;
+ }
}
/**
@@ -8035,6 +8060,10 @@
@Override
public boolean isProvisioningAllowed(String action) {
+ if (!mHasFeature) {
+ return false;
+ }
+
final int callingUserId = mInjector.userHandleGetCallingUserId();
if (DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE.equals(action)) {
if (!hasFeatureManagedUsers()) {
@@ -8099,23 +8128,55 @@
throw new IllegalArgumentException("Unknown provisioning action " + action);
}
- private boolean isDeviceOwnerProvisioningAllowed(int callingUserId) {
- synchronized (this) {
- if (mOwners.hasDeviceOwner()) {
- return false;
+ /*
+ * The device owner can only be set before the setup phase of the primary user has completed,
+ * except for adb command if no accounts or additional users are present on the device.
+ */
+ private synchronized @DeviceOwnerPreConditionCode int checkSetDeviceOwnerPreCondition(
+ int deviceOwnerUserId, boolean isAdb) {
+ if (mOwners.hasDeviceOwner()) {
+ return CODE_HAS_DEVICE_OWNER;
+ }
+ if (mOwners.hasProfileOwner(deviceOwnerUserId)) {
+ return CODE_USER_HAS_PROFILE_OWNER;
+ }
+ if (!mUserManager.isUserRunning(new UserHandle(deviceOwnerUserId))) {
+ return CODE_USER_NOT_RUNNING;
+ }
+ if (isAdb) {
+ // if shell command runs after user setup completed check device status. Otherwise, OK.
+ if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
+ if (!mInjector.userManagerIsSplitSystemUser()) {
+ if (mUserManager.getUserCount() > 1) {
+ return CODE_NONSYSTEM_USER_EXISTS;
+ }
+ if (AccountManager.get(mContext).getAccounts().length > 0) {
+ return CODE_ACCOUNTS_NOT_EMPTY;
+ }
+ } else {
+ // STOPSHIP Do proper check in split user mode
+ }
}
+ return CODE_OK;
+ } else {
+ if (!mInjector.userManagerIsSplitSystemUser()) {
+ // In non-split user mode, DO has to be user 0
+ if (deviceOwnerUserId != UserHandle.USER_SYSTEM) {
+ return CODE_NOT_SYSTEM_USER;
+ }
+ // In non-split user mode, only provision DO before setup wizard completes
+ if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
+ return CODE_USER_SETUP_COMPLETED;
+ }
+ } else {
+ // STOPSHIP Do proper check in split user mode
+ }
+ return CODE_OK;
}
- if (getProfileOwner(callingUserId) != null) {
- return false;
- }
- if (mInjector.settingsGlobalGetInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
- return false;
- }
- if (callingUserId != UserHandle.USER_SYSTEM) {
- // Device owner provisioning can only be initiated from system user.
- return false;
- }
- return true;
+ }
+
+ private boolean isDeviceOwnerProvisioningAllowed(int deviceOwnerUserId) {
+ return CODE_OK == checkSetDeviceOwnerPreCondition(deviceOwnerUserId, /* isAdb */ false);
}
private boolean hasFeatureManagedUsers() {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
index 117ba15..6d42dc9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
@@ -19,8 +19,12 @@
import android.annotation.IntDef;
import android.app.Notification;
import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.text.format.DateUtils;
import com.android.internal.R;
@@ -37,79 +41,62 @@
@Retention(RetentionPolicy.SOURCE)
@IntDef({
- NOTIFICATION_BUGREPORT_STARTED,
- NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED,
- NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED
+ DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED,
+ DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED,
+ DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED
})
@interface RemoteBugreportNotificationType {}
- static final int NOTIFICATION_BUGREPORT_STARTED = 1;
- static final int NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED = 2;
- static final int NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED = 3;
static final long REMOTE_BUGREPORT_TIMEOUT_MILLIS = 10 * DateUtils.MINUTE_IN_MILLIS;
static final String CTL_STOP = "ctl.stop";
static final String REMOTE_BUGREPORT_SERVICE = "bugreportremote";
- static final String ACTION_REMOTE_BUGREPORT_DISPATCH =
- "android.intent.action.REMOTE_BUGREPORT_DISPATCH";
- static final String ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED =
- "com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED";
- static final String ACTION_REMOTE_BUGREPORT_SHARING_DECLINED =
- "com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED";
- static final String EXTRA_REMOTE_BUGREPORT_HASH = "android.intent.extra.REMOTE_BUGREPORT_HASH";
-
static final String BUGREPORT_MIMETYPE = "application/vnd.android.bugreport";
static Notification buildNotification(Context context,
@RemoteBugreportNotificationType int type) {
+ Intent dialogIntent = new Intent(Settings.ACTION_SHOW_REMOTE_BUGREPORT_DIALOG);
+ dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ dialogIntent.putExtra(DevicePolicyManager.EXTRA_BUGREPORT_NOTIFICATION_TYPE, type);
+ PendingIntent pendingDialogIntent = PendingIntent.getActivityAsUser(context, type,
+ dialogIntent, 0, null, UserHandle.CURRENT);
+
Notification.Builder builder = new Notification.Builder(context)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setOngoing(true)
.setLocalOnly(true)
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setContentIntent(pendingDialogIntent)
.setColor(context.getColor(
com.android.internal.R.color.system_notification_accent_color));
- if (type == NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
+ if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
builder.setContentTitle(context.getString(
- R.string.sharing_remote_bugreport_notification_title))
- .setContentText(context.getString(
- R.string.sharing_remote_bugreport_notification_message))
- .setPriority(Notification.PRIORITY_HIGH)
- .setProgress(0, 0, true)
- .setStyle(new Notification.BigTextStyle().bigText(context.getString(
- R.string.sharing_remote_bugreport_notification_message)));
- } else {
+ R.string.sharing_remote_bugreport_notification_title))
+ .setProgress(0, 0, true);
+ } else if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED) {
+ builder.setContentTitle(context.getString(
+ R.string.taking_remote_bugreport_notification_title))
+ .setProgress(0, 0, true);
+ } else if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED) {
PendingIntent pendingIntentAccept = PendingIntent.getBroadcast(context, NOTIFICATION_ID,
- new Intent(ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED),
+ new Intent(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED),
PendingIntent.FLAG_CANCEL_CURRENT);
PendingIntent pendingIntentDecline = PendingIntent.getBroadcast(context,
- NOTIFICATION_ID, new Intent(ACTION_REMOTE_BUGREPORT_SHARING_DECLINED),
+ NOTIFICATION_ID, new Intent(
+ DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED),
PendingIntent.FLAG_CANCEL_CURRENT);
builder.addAction(new Notification.Action.Builder(null /* icon */, context.getString(
- R.string.share_remote_bugreport_notification_decline),
- pendingIntentDecline).build())
+ R.string.decline_remote_bugreport_action), pendingIntentDecline).build())
.addAction(new Notification.Action.Builder(null /* icon */, context.getString(
- R.string.share_remote_bugreport_notification_accept),
- pendingIntentAccept).build())
+ R.string.share_remote_bugreport_action), pendingIntentAccept).build())
.setContentTitle(context.getString(
- R.string.share_remote_bugreport_notification_title));
-
- if (type == NOTIFICATION_BUGREPORT_STARTED) {
- builder.setContentText(context.getString(
- R.string.share_remote_bugreport_notification_message))
- .setStyle(new Notification.BigTextStyle().bigText(context.getString(
- R.string.share_remote_bugreport_notification_message)))
- .setProgress(0, 0, true)
- .setPriority(Notification.PRIORITY_MAX)
- .setVibrate(new long[0]);
- } else if (type == NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED) {
- builder.setContentText(context.getString(
- R.string.share_finished_remote_bugreport_notification_message))
- .setStyle(new Notification.BigTextStyle().bigText(context.getString(
- R.string.share_finished_remote_bugreport_notification_message)))
- .setPriority(Notification.PRIORITY_HIGH);
- }
+ R.string.share_remote_bugreport_notification_title))
+ .setContentText(context.getString(
+ R.string.share_remote_bugreport_notification_message_finished))
+ .setStyle(new Notification.BigTextStyle().bigText(context.getString(
+ R.string.share_remote_bugreport_notification_message_finished)));
}
return builder.build();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9aa2b94..b8c31e3 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -431,6 +431,24 @@
mPackageManager = mSystemContext.getPackageManager();
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ // Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename
+ // A/B artifacts after boot, before anything else might touch/need them.
+ // Note: this isn't needed during decryption (we don't have /data anyways).
+ if (!mOnlyCore) {
+ boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
+ false);
+ if (!disableOtaDexopt) {
+ traceBeginAndSlog("StartOtaDexOptService");
+ try {
+ OtaDexoptService.main(mSystemContext, mPackageManagerService);
+ } catch (Throwable e) {
+ reportWtf("starting OtaDexOptService", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+ }
+ }
+
traceBeginAndSlog("StartUserManagerService");
ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance());
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
@@ -1124,19 +1142,6 @@
reportWtf("starting BackgroundDexOptService", e);
}
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-
- // Manages A/B OTA dexopting.
- boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
- false);
- if (!disableOtaDexopt) {
- traceBeginAndSlog("StartOtaDexOptService");
- try {
- OtaDexoptService.main(mSystemContext, mPackageManagerService);
- } catch (Throwable e) {
- reportWtf("starting BackgroundDexOptService", e);
- }
- Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- }
}
mSystemServiceManager.startService(LauncherAppsService.class);
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 4f99bff..e2562cd 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -84,10 +84,10 @@
public class DhcpClient extends StateMachine {
private static final String TAG = "DhcpClient";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean STATE_DBG = false;
private static final boolean MSG_DBG = false;
- private static final boolean PACKET_DBG = true;
+ private static final boolean PACKET_DBG = false;
// Timers and timeouts.
private static final int SECONDS = 1000;
@@ -342,14 +342,14 @@
@Override
public void run() {
- maybeLog("Receive thread started");
+ if (DBG) Log.d(TAG, "Receive thread started");
while (!stopped) {
int length = 0; // Or compiler can't tell it's initialized if a parse error occurs.
try {
length = Os.read(mPacketSock, mPacket, 0, mPacket.length);
DhcpPacket packet = null;
packet = DhcpPacket.decodeFullPacket(mPacket, length, DhcpPacket.ENCAP_L2);
- maybeLog("Received packet: " + packet);
+ if (DBG) Log.d(TAG, "Received packet: " + packet);
sendMessage(CMD_RECEIVED_PACKET, packet);
} catch (IOException|ErrnoException e) {
if (!stopped) {
@@ -362,7 +362,7 @@
}
}
}
- maybeLog("Receive thread stopped");
+ if (DBG) Log.d(TAG, "Receive thread stopped");
}
}
@@ -373,12 +373,12 @@
private boolean transmitPacket(ByteBuffer buf, String description, Inet4Address to) {
try {
if (to.equals(INADDR_BROADCAST)) {
- maybeLog("Broadcasting " + description);
+ if (DBG) Log.d(TAG, "Broadcasting " + description);
Os.sendto(mPacketSock, buf.array(), 0, buf.limit(), 0, mInterfaceBroadcastAddr);
} else {
// It's safe to call getpeername here, because we only send unicast packets if we
// have an IP address, and we connect the UDP socket in DhcpHaveAddressState#enter.
- maybeLog("Unicasting " + description + " to " + Os.getpeername(mUdpSock));
+ if (DBG) Log.d(TAG, "Unicasting " + description + " to " + Os.getpeername(mUdpSock));
Os.write(mUdpSock, buf);
}
} catch(ErrnoException|IOException e) {
@@ -454,10 +454,6 @@
mController.sendMessage(CMD_ON_QUIT);
}
- private void maybeLog(String msg) {
- if (DBG) Log.d(TAG, msg);
- }
-
abstract class LoggingState extends State {
public void enter() {
if (STATE_DBG) Log.d(TAG, "Entering state " + getName());
@@ -592,7 +588,7 @@
transitionTo(mStoppedState);
return HANDLED;
case CMD_ONESHOT_TIMEOUT:
- maybeLog("Timed out");
+ if (DBG) Log.d(TAG, "Timed out");
notifyFailure();
return HANDLED;
default:
@@ -790,7 +786,7 @@
@Override
public void exit() {
- maybeLog("Clearing IP address");
+ if (DBG) Log.d(TAG, "Clearing IP address");
setIpAddress(new LinkAddress("0.0.0.0/0"));
}
}
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index afae956..c7c5015 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -63,7 +63,7 @@
* @hide
*/
public class IpManager extends StateMachine {
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean VDBG = false;
// For message logging.
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index 88155f7..5b4fd50 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -132,7 +132,7 @@
*/
public class IpReachabilityMonitor {
private static final String TAG = "IpReachabilityMonitor";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean VDBG = false;
public interface Callback {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 212b37c..8c47087 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -969,6 +969,8 @@
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+
// Make sure the admin packge is installed to each user.
setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_SYSTEM_USER_UID);
@@ -1008,6 +1010,7 @@
* finds the right component from a package name upon migration.
*/
public void testDeviceOwnerMigration() throws Exception {
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
checkDeviceOwnerWithMultipleDeviceAdmins();
// Overwrite the device owner setting and clears the clas name.
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 6ab0b99..837b4a4 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -75,7 +75,7 @@
*/
public class VoiceInteractionManagerService extends SystemService {
static final String TAG = "VoiceInteractionManagerService";
- static final boolean DEBUG = true;
+ static final boolean DEBUG = false;
final Context mContext;
final ContentResolver mResolver;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 1278c07..cd1c5e9 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -637,7 +637,7 @@
sDefaults.putBoolean(KEY_SHOW_CDMA_CHOICES_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL, true);
sDefaults.putBoolean(KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL, true);
- sDefaults.putBoolean(KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL, true);
+ sDefaults.putBoolean(KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL, false);
sDefaults.putBoolean(KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL, true);
sDefaults.putBoolean(KEY_USE_HFA_FOR_PROVISIONING_BOOL, false);
sDefaults.putBoolean(KEY_USE_OTASP_FOR_PROVISIONING_BOOL, false);
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index ad007c6..39a9295 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -36,7 +36,7 @@
public class ServiceState implements Parcelable {
static final String LOG_TAG = "PHONE";
- static final boolean DBG = true;
+ static final boolean DBG = false;
static final boolean VDBG = false; // STOPSHIP if true
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index e90be91..b482811 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4403,7 +4403,6 @@
Log.e(TAG, "Error calling ITelephony#getDataEnabled", e);
} catch (NullPointerException e) {
}
- Log.d(TAG, "getDataEnabled: retVal=" + retVal);
return retVal;
}
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index c34d4a9..e851c8d 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -518,6 +518,14 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
+ int badgeDensity) {
+ throw new UnsupportedOperationException();
+ }
+
+
@Override
public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
throw new UnsupportedOperationException();
diff --git a/tests/HwAccelerationTest/res/drawable/default_wallpaper.png b/tests/HwAccelerationTest/res/drawable/default_wallpaper.png
index 91ad252..187a6c0 100644
--- a/tests/HwAccelerationTest/res/drawable/default_wallpaper.png
+++ b/tests/HwAccelerationTest/res/drawable/default_wallpaper.png
Binary files differ
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java b/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java
index c8a8d6c..6463e1f 100644
--- a/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java
+++ b/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java
@@ -47,7 +47,7 @@
OnBufferingUpdateListener, OnCompletionListener, OnErrorListener,
OnAudioFocusChangeListener {
private static final String TAG = "MediaPlayerManager";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static long sDebugInstanceId = 0;
private static final String[] SUPPORTED_FEATURES = {
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
index 4770c05..3ca96d2 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
@@ -40,7 +40,7 @@
public class TestSoundTriggerActivity extends Activity {
private static final String TAG = "TestSoundTriggerActivity";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private SoundTriggerUtil mSoundTriggerUtil;
private Random mRandom;
diff --git a/tests/SoundTriggerTests/Android.mk b/tests/SoundTriggerTests/Android.mk
index 407a9d7..ac562b9 100644
--- a/tests/SoundTriggerTests/Android.mk
+++ b/tests/SoundTriggerTests/Android.mk
@@ -18,7 +18,14 @@
LOCAL_MODULE_TAGS := tests
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+ifeq ($(SOUND_TRIGGER_USE_STUB_MODULE), 1)
+ LOCAL_SRC_FILES := $(call all-subdir-java-files)
+ LOCAL_PRIVILEGED_MODULE := true
+ LOCAL_CERTIFICATE := platform
+ TARGET_OUT_DATA_APPS_PRIVILEGED := $(TARGET_OUT_DATA)/priv-app
+else
+ LOCAL_SRC_FILES := src/android/hardware/soundtrigger/SoundTriggerTest.java
+endif
LOCAL_JAVA_LIBRARIES := android.test.runner
diff --git a/tests/SoundTriggerTests/AndroidManifest.xml b/tests/SoundTriggerTests/AndroidManifest.xml
index 5e5a108..e8b9dd3 100644
--- a/tests/SoundTriggerTests/AndroidManifest.xml
+++ b/tests/SoundTriggerTests/AndroidManifest.xml
@@ -14,7 +14,10 @@
limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.hardware.soundtrigger">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.hardware.soundtrigger">
+ <uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER" />
+
<application>
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java
new file mode 100644
index 0000000..7acb472
--- /dev/null
+++ b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.soundtrigger;
+
+import java.util.Random;
+import java.util.UUID;
+
+import android.content.Context;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
+import android.media.soundtrigger.SoundTriggerManager;
+import android.os.ParcelUuid;
+import android.os.ServiceManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.app.ISoundTriggerService;
+
+import java.util.Arrays;
+import java.util.Random;
+import java.util.UUID;
+
+public class GenericSoundModelTest extends AndroidTestCase {
+ private Random mRandom = new Random();
+
+ @SmallTest
+ public void testUpdateGenericSoundModel() throws Exception {
+ Context context = getContext();
+ ISoundTriggerService mSoundTriggerService = ISoundTriggerService.Stub.asInterface(
+ ServiceManager.getService(Context.SOUND_TRIGGER_SERVICE));
+ SoundTriggerManager mSoundTriggerManager = (SoundTriggerManager) context.getSystemService(
+ Context.SOUND_TRIGGER_SERVICE);
+
+ byte[] data = new byte[1024];
+ mRandom.nextBytes(data);
+ UUID modelUuid = UUID.randomUUID();
+ UUID mVendorUuid = UUID.randomUUID();
+ GenericSoundModel model = new GenericSoundModel(modelUuid, mVendorUuid, data);
+
+ mSoundTriggerService.updateSoundModel(model);
+ GenericSoundModel returnedModel =
+ mSoundTriggerService.getSoundModel(new ParcelUuid(modelUuid));
+
+ assertEquals(model, returnedModel);
+
+ // Cleanup sound model
+ mSoundTriggerService.deleteSoundModel(new ParcelUuid(modelUuid));
+ }
+
+
+ @SmallTest
+ public void testDeleteGenericSoundModel() throws Exception {
+ Context context = getContext();
+ ISoundTriggerService mSoundTriggerService = ISoundTriggerService.Stub.asInterface(
+ ServiceManager.getService(Context.SOUND_TRIGGER_SERVICE));
+ SoundTriggerManager mSoundTriggerManager = (SoundTriggerManager) context.getSystemService(
+ Context.SOUND_TRIGGER_SERVICE);
+
+ byte[] data = new byte[1024];
+ mRandom.nextBytes(data);
+ UUID modelUuid = UUID.randomUUID();
+ UUID mVendorUuid = UUID.randomUUID();
+ GenericSoundModel model = new GenericSoundModel(modelUuid, mVendorUuid, data);
+
+ mSoundTriggerService.updateSoundModel(model);
+ mSoundTriggerService.deleteSoundModel(new ParcelUuid(modelUuid));
+
+ GenericSoundModel returnedModel =
+ mSoundTriggerService.getSoundModel(new ParcelUuid(modelUuid));
+ assertEquals(null, returnedModel);
+ }
+}
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 2a3f143..0da1bb1 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -93,11 +93,7 @@
.setSmallIcon(R.drawable.icon2)
.setContentTitle("Min priority")
.setLights(0xff0000ff, 1, 0)
- .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
- .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
- getPackageName() + "/raw/ringer"))
.setPriority(Notification.PRIORITY_MIN)
- .setFullScreenIntent(makeIntent2(), false)
.build();
mNM.notify(7000, n);
}
@@ -125,11 +121,7 @@
.setSmallIcon(R.drawable.icon2)
.setContentTitle("Low priority")
.setLights(0xff0000ff, 1, 0)
- .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
- .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
- getPackageName() + "/raw/ringer"))
.setPriority(Notification.PRIORITY_LOW)
- .setFullScreenIntent(makeIntent2(), false)
.build();
mNM.notify(7002, n);
}
@@ -141,11 +133,7 @@
.setSmallIcon(R.drawable.icon2)
.setContentTitle("Default priority")
.setLights(0xff0000ff, 1, 0)
- .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
- .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
- getPackageName() + "/raw/ringer"))
.setPriority(Notification.PRIORITY_DEFAULT)
- .setFullScreenIntent(makeIntent2(), false)
.build();
mNM.notify(7004, n);
}
@@ -161,7 +149,6 @@
.setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
getPackageName() + "/raw/ringer"))
.setPriority(Notification.PRIORITY_HIGH)
- .setFullScreenIntent(makeIntent2(), false)
.build();
mNM.notify(7006, n);
}
@@ -179,7 +166,7 @@
.setPriority(Notification.PRIORITY_MAX)
.setFullScreenIntent(makeIntent2(), false)
.build();
- mNM.notify(7008, n);
+ mNM.notify(7007, n);
}
},
new Test("Max priority with delay") {
@@ -202,6 +189,64 @@
mNM.notify(7008, n);
}
},
+ new Test("public notification") {
+ public void run()
+ {
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle("public notification")
+ .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+ .setPriority(Notification.PRIORITY_DEFAULT)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .build();
+ mNM.notify(7009, n);
+ }
+ },
+ new Test("private notification, no public") {
+ public void run()
+ {
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle("private only notification")
+ .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+ .setPriority(Notification.PRIORITY_DEFAULT)
+ .setVisibility(Notification.VISIBILITY_PRIVATE)
+ .build();
+ mNM.notify(7010, n);
+ }
+ },
+ new Test("private notification, has public") {
+ public void run()
+ {
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle("private version of notification")
+ .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+ .setPriority(Notification.PRIORITY_DEFAULT)
+ .setVisibility(Notification.VISIBILITY_PRIVATE)
+ .setPublicVersion(new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle("public notification of private notification")
+ .setPriority(Notification.PRIORITY_DEFAULT)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .build())
+ .build();
+ mNM.notify(7011, n);
+ }
+ },
+ new Test("secret notification") {
+ public void run()
+ {
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle("secret notification")
+ .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+ .setPriority(Notification.PRIORITY_DEFAULT)
+ .setVisibility(Notification.VISIBILITY_SECRET)
+ .build();
+ mNM.notify(7012, n);
+ }
+ },
new Test("Off") {
public void run() {
PowerManager pm = (PowerManager)NotificationTestList.this.getSystemService(Context.POWER_SERVICE);
diff --git a/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
index 2494db7..54c944f9 100644
--- a/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
+++ b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
@@ -31,7 +31,7 @@
public class TestEnrollmentActivity extends Activity {
private static final String TAG = "TestEnrollmentActivity";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
/** Keyphrase related constants, must match those defined in enrollment_application.xml */
private static final int KEYPHRASE_ID = 101;
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 3b01827..cbd8480 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -373,7 +373,7 @@
void AaptLocaleValue::initFromResTable(const ResTable_config& config) {
config.unpackLanguage(language);
config.unpackRegion(region);
- if (config.localeScriptWasProvided) {
+ if (config.localeScript[0] && !config.localeScriptWasComputed) {
memcpy(script, config.localeScript, sizeof(config.localeScript));
}
@@ -388,10 +388,10 @@
if (script[0]) {
memcpy(out->localeScript, script, sizeof(out->localeScript));
- out->localeScriptWasProvided = true;
+ out->localeScriptWasComputed = false;
} else {
out->computeScript();
- out->localeScriptWasProvided = false;
+ out->localeScriptWasComputed = true;
}
if (variant[0]) {
diff --git a/tools/aapt2/Locale.cpp b/tools/aapt2/Locale.cpp
index 6acf3b0..12f56fc 100644
--- a/tools/aapt2/Locale.cpp
+++ b/tools/aapt2/Locale.cpp
@@ -253,7 +253,7 @@
void LocaleValue::initFromResTable(const ResTable_config& config) {
config.unpackLanguage(language);
config.unpackRegion(region);
- if (config.localeScriptWasProvided) {
+ if (config.localeScript[0] && !config.localeScriptWasComputed) {
memcpy(script, config.localeScript, sizeof(config.localeScript));
}
@@ -268,10 +268,10 @@
if (script[0]) {
memcpy(out->localeScript, script, sizeof(out->localeScript));
- out->localeScriptWasProvided = true;
+ out->localeScriptWasComputed = false;
} else {
out->computeScript();
- out->localeScriptWasProvided = false;
+ out->localeScriptWasComputed = true;
}
if (variant[0]) {
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index c2ad9ef..663e1e2 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -40,10 +40,8 @@
built_ext_classes := $(call java-lib-files,ext)
built_ext_data := $(call intermediates-dir-for, \
JAVA_LIBRARIES,ext,,COMMON)/javalib.jar
-built_icudata_dep := $(call java-lib-deps,icu4j-icudata-jarjar)
-built_icudata_data := $(call java-lib-files,icu4j-icudata-jarjar)
-built_icutzdata_dep := $(call java-lib-deps,icu4j-icutzdata-jarjar)
-built_icutzdata_data := $(call java-lib-files,icu4j-icutzdata-jarjar)
+built_icudata_dep := $(call java-lib-deps,icu4j-icudata-host-jarjar,HOST)
+built_icutzdata_dep := $(call java-lib-deps,icu4j-icutzdata-host-jarjar,HOST)
built_layoutlib_create_jar := $(call intermediates-dir-for, \
JAVA_LIBRARIES,layoutlib_create,HOST)/javalib.jar
@@ -77,8 +75,8 @@
$(built_core_classes) \
$(built_framework_classes) \
$(built_ext_classes) \
- $(built_icudata_data) \
- $(built_icutzdata_data) \
+ $(built_icudata_dep) \
+ $(built_icutzdata_dep) \
$(built_ext_data)
$(hide) ls -l $(built_framework_classes)
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index db4c6dc6..ae42ba6 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -305,6 +305,12 @@
return defValue;
}
+ @Override
+ public ComplexColor getComplexColor(int index) {
+ // TODO: Support GradientColor
+ return getColorStateList(index);
+ }
+
/**
* Retrieve the ColorStateList for the attribute at <var>index</var>.
* The value may be either a single solid color or a reference to
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index c4fbd56..fa880f0 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -142,7 +142,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_setBitmap(long canvas, Bitmap bitmap) {
+ public static void native_setBitmap(long canvas, Bitmap bitmap) {
Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
if (canvasDelegate == null || bitmapDelegate==null) {
@@ -153,7 +153,7 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_isOpaque(long nativeCanvas) {
+ public static boolean native_isOpaque(long nativeCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -164,10 +164,10 @@
}
@LayoutlibDelegate
- /*package*/ static void native_setHighContrastText(long nativeCanvas, boolean highContrastText){}
+ public static void native_setHighContrastText(long nativeCanvas, boolean highContrastText){}
@LayoutlibDelegate
- /*package*/ static int native_getWidth(long nativeCanvas) {
+ public static int native_getWidth(long nativeCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -178,7 +178,7 @@
}
@LayoutlibDelegate
- /*package*/ static int native_getHeight(long nativeCanvas) {
+ public static int native_getHeight(long nativeCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -189,7 +189,7 @@
}
@LayoutlibDelegate
- /*package*/ static int native_save(long nativeCanvas, int saveFlags) {
+ public static int native_save(long nativeCanvas, int saveFlags) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -200,7 +200,7 @@
}
@LayoutlibDelegate
- /*package*/ static int native_saveLayer(long nativeCanvas, float l,
+ public static int native_saveLayer(long nativeCanvas, float l,
float t, float r, float b,
long paint, int layerFlags) {
// get the delegate from the native int.
@@ -219,7 +219,7 @@
}
@LayoutlibDelegate
- /*package*/ static int native_saveLayerAlpha(long nativeCanvas, float l,
+ public static int native_saveLayerAlpha(long nativeCanvas, float l,
float t, float r, float b,
int alpha, int layerFlags) {
// get the delegate from the native int.
@@ -232,7 +232,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_restore(long nativeCanvas, boolean throwOnUnderflow) {
+ public static void native_restore(long nativeCanvas, boolean throwOnUnderflow) {
// FIXME: implement throwOnUnderflow.
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -244,7 +244,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_restoreToCount(long nativeCanvas, int saveCount,
+ public static void native_restoreToCount(long nativeCanvas, int saveCount,
boolean throwOnUnderflow) {
// FIXME: implement throwOnUnderflow.
// get the delegate from the native int.
@@ -257,7 +257,7 @@
}
@LayoutlibDelegate
- /*package*/ static int native_getSaveCount(long nativeCanvas) {
+ public static int native_getSaveCount(long nativeCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -268,7 +268,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_translate(long nativeCanvas, float dx, float dy) {
+ public static void native_translate(long nativeCanvas, float dx, float dy) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -279,7 +279,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_scale(long nativeCanvas, float sx, float sy) {
+ public static void native_scale(long nativeCanvas, float sx, float sy) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -290,7 +290,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_rotate(long nativeCanvas, float degrees) {
+ public static void native_rotate(long nativeCanvas, float degrees) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -301,7 +301,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_skew(long nativeCanvas, float kx, float ky) {
+ public static void native_skew(long nativeCanvas, float kx, float ky) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -325,7 +325,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_concat(long nCanvas, long nMatrix) {
+ public static void native_concat(long nCanvas, long nMatrix) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
if (canvasDelegate == null) {
@@ -353,7 +353,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_setMatrix(long nCanvas, long nMatrix) {
+ public static void native_setMatrix(long nCanvas, long nMatrix) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
if (canvasDelegate == null) {
@@ -383,7 +383,7 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_clipRect(long nCanvas,
+ public static boolean native_clipRect(long nCanvas,
float left, float top,
float right, float bottom,
int regionOp) {
@@ -397,7 +397,7 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_clipPath(long nativeCanvas,
+ public static boolean native_clipPath(long nativeCanvas,
long nativePath,
int regionOp) {
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -414,7 +414,7 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_clipRegion(long nativeCanvas,
+ public static boolean native_clipRegion(long nativeCanvas,
long nativeRegion,
int regionOp) {
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -431,7 +431,7 @@
}
@LayoutlibDelegate
- /*package*/ static void nativeSetDrawFilter(long nativeCanvas, long nativeFilter) {
+ public static void nativeSetDrawFilter(long nativeCanvas, long nativeFilter) {
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return;
@@ -446,7 +446,7 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_getClipBounds(long nativeCanvas,
+ public static boolean native_getClipBounds(long nativeCanvas,
Rect bounds) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -467,7 +467,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_getCTM(long canvas, long matrix) {
+ public static void native_getCTM(long canvas, long matrix) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
if (canvasDelegate == null) {
@@ -484,13 +484,13 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_quickReject(long nativeCanvas, long path) {
+ public static boolean native_quickReject(long nativeCanvas, long path) {
// FIXME properly implement quickReject
return false;
}
@LayoutlibDelegate
- /*package*/ static boolean native_quickReject(long nativeCanvas,
+ public static boolean native_quickReject(long nativeCanvas,
float left, float top,
float right, float bottom) {
// FIXME properly implement quickReject
@@ -498,7 +498,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawColor(long nativeCanvas, final int color, final int mode) {
+ public static void native_drawColor(long nativeCanvas, final int color, final int mode) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -529,14 +529,14 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawPaint(long nativeCanvas, long paint) {
+ public static void native_drawPaint(long nativeCanvas, long paint) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Canvas.drawPaint is not supported.", null, null /*data*/);
}
@LayoutlibDelegate
- /*package*/ static void native_drawPoint(long nativeCanvas, float x, float y,
+ public static void native_drawPoint(long nativeCanvas, float x, float y,
long nativePaint) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -544,7 +544,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawPoints(long nativeCanvas, float[] pts, int offset, int count,
+ public static void native_drawPoints(long nativeCanvas, float[] pts, int offset, int count,
long nativePaint) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -552,7 +552,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawLine(long nativeCanvas,
+ public static void native_drawLine(long nativeCanvas,
final float startX, final float startY, final float stopX, final float stopY,
long paint) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -565,7 +565,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawLines(long nativeCanvas,
+ public static void native_drawLines(long nativeCanvas,
final float[] pts, final int offset, final int count,
long nativePaint) {
draw(nativeCanvas, nativePaint, false /*compositeOnly*/,
@@ -581,7 +581,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawRect(long nativeCanvas,
+ public static void native_drawRect(long nativeCanvas,
final float left, final float top, final float right, final float bottom, long paint) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -607,7 +607,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawOval(long nativeCanvas, final float left,
+ public static void native_drawOval(long nativeCanvas, final float left,
final float top, final float right, final float bottom, long paint) {
if (right > left && bottom > top) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -634,7 +634,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawCircle(long nativeCanvas,
+ public static void native_drawCircle(long nativeCanvas,
float cx, float cy, float radius, long paint) {
native_drawOval(nativeCanvas,
cx - radius, cy - radius, cx + radius, cy + radius,
@@ -642,7 +642,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawArc(long nativeCanvas,
+ public static void native_drawArc(long nativeCanvas,
final float left, final float top, final float right, final float bottom,
final float startAngle, final float sweep,
final boolean useCenter, long paint) {
@@ -674,7 +674,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawRoundRect(long nativeCanvas,
+ public static void native_drawRoundRect(long nativeCanvas,
final float left, final float top, final float right, final float bottom,
final float rx, final float ry, long paint) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -704,7 +704,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawPath(long nativeCanvas, long path, long paint) {
+ public static void native_drawPath(long nativeCanvas, long path, long paint) {
final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path);
if (pathDelegate == null) {
return;
@@ -756,7 +756,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawRegion(long nativeCanvas, long nativeRegion,
+ public static void native_drawRegion(long nativeCanvas, long nativeRegion,
long nativePaint) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -764,7 +764,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawNinePatch(Canvas thisCanvas, long nativeCanvas,
+ public static void native_drawNinePatch(Canvas thisCanvas, long nativeCanvas,
long nativeBitmap, long ninePatch, final float dstLeft, final float dstTop,
final float dstRight, final float dstBottom, long nativePaintOrZero,
final int screenDensity, final int bitmapDensity) {
@@ -811,7 +811,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
+ public static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
float left, float top,
long nativePaintOrZero,
int canvasDensity,
@@ -833,7 +833,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
+ public static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
float srcLeft, float srcTop, float srcRight, float srcBottom,
float dstLeft, float dstTop, float dstRight, float dstBottom,
long nativePaintOrZero, int screenDensity, int bitmapDensity) {
@@ -849,7 +849,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawBitmap(long nativeCanvas, int[] colors,
+ public static void native_drawBitmap(long nativeCanvas, int[] colors,
int offset, int stride, final float x,
final float y, int width, int height,
boolean hasAlpha,
@@ -874,7 +874,7 @@
}
@LayoutlibDelegate
- /*package*/ static void nativeDrawBitmapMatrix(long nCanvas, Bitmap bitmap,
+ public static void nativeDrawBitmapMatrix(long nCanvas, Bitmap bitmap,
long nMatrix, long nPaint) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
@@ -915,7 +915,7 @@
}
@LayoutlibDelegate
- /*package*/ static void nativeDrawBitmapMesh(long nCanvas, Bitmap bitmap,
+ public static void nativeDrawBitmapMesh(long nCanvas, Bitmap bitmap,
int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors,
int colorOffset, long nPaint) {
// FIXME
@@ -924,7 +924,7 @@
}
@LayoutlibDelegate
- /*package*/ static void nativeDrawVertices(long nCanvas, int mode, int n,
+ public static void nativeDrawVertices(long nCanvas, int mode, int n,
float[] verts, int vertOffset,
float[] texs, int texOffset,
int[] colors, int colorOffset,
@@ -936,14 +936,14 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawText(long nativeCanvas, char[] text, int index, int count,
+ public static void native_drawText(long nativeCanvas, char[] text, int index, int count,
float startX, float startY, int flags, long paint, long typeface) {
drawText(nativeCanvas, text, index, count, startX, startY, (flags & 1) != 0,
paint, typeface);
}
@LayoutlibDelegate
- /*package*/ static void native_drawText(long nativeCanvas, String text,
+ public static void native_drawText(long nativeCanvas, String text,
int start, int end, float x, float y, final int flags, long paint,
long typeface) {
int count = end - start;
@@ -954,7 +954,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawTextRun(long nativeCanvas, String text,
+ public static void native_drawTextRun(long nativeCanvas, String text,
int start, int end, int contextStart, int contextEnd,
float x, float y, boolean isRtl, long paint, long typeface) {
int count = end - start;
@@ -965,14 +965,14 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawTextRun(long nativeCanvas, char[] text,
+ public static void native_drawTextRun(long nativeCanvas, char[] text,
int start, int count, int contextStart, int contextCount,
float x, float y, boolean isRtl, long paint, long typeface) {
drawText(nativeCanvas, text, start, count, x, y, isRtl, paint, typeface);
}
@LayoutlibDelegate
- /*package*/ static void native_drawTextOnPath(long nativeCanvas,
+ public static void native_drawTextOnPath(long nativeCanvas,
char[] text, int index,
int count, long path,
float hOffset,
@@ -984,7 +984,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_drawTextOnPath(long nativeCanvas,
+ public static void native_drawTextOnPath(long nativeCanvas,
String text, long path,
float hOffset,
float vOffset,
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 514d785..839c182 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -223,6 +223,10 @@
return mColorFilter;
}
+ public void setColorFilter(long colorFilterPtr) {
+ mColorFilter = ColorFilter_Delegate.getDelegate(colorFilterPtr);
+ }
+
/**
* Returns the {@link Shader} delegate or null if none have been set
*
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index e1da27b..08f0cb4 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -572,7 +572,7 @@
return null;
}
- private static void addPath(long destPath, long srcPath, AffineTransform transform) {
+ public static void addPath(long destPath, long srcPath, AffineTransform transform) {
Path_Delegate destPathDelegate = sManager.getDelegate(destPath);
if (destPathDelegate == null) {
return;
@@ -630,7 +630,7 @@
* Fills the given {@link RectF} with the path bounds.
* @param bounds the RectF to be filled.
*/
- private void fillBounds(RectF bounds) {
+ public void fillBounds(RectF bounds) {
Rectangle2D rect = mPath.getBounds2D();
bounds.left = (float)rect.getMinX();
bounds.right = (float)rect.getMaxX();
@@ -644,7 +644,7 @@
* @param x The x-coordinate of the start of a new contour
* @param y The y-coordinate of the start of a new contour
*/
- private void moveTo(float x, float y) {
+ public void moveTo(float x, float y) {
mPath.moveTo(mLastX = x, mLastY = y);
}
@@ -658,7 +658,7 @@
* @param dy The amount to add to the y-coordinate of the end of the
* previous contour, to specify the start of a new contour
*/
- private void rMoveTo(float dx, float dy) {
+ public void rMoveTo(float dx, float dy) {
dx += mLastX;
dy += mLastY;
mPath.moveTo(mLastX = dx, mLastY = dy);
@@ -672,7 +672,7 @@
* @param x The x-coordinate of the end of a line
* @param y The y-coordinate of the end of a line
*/
- private void lineTo(float x, float y) {
+ public void lineTo(float x, float y) {
if (!hasPoints()) {
mPath.moveTo(mLastX = 0, mLastY = 0);
}
@@ -689,7 +689,7 @@
* @param dy The amount to add to the y-coordinate of the previous point on
* this contour, to specify a line
*/
- private void rLineTo(float dx, float dy) {
+ public void rLineTo(float dx, float dy) {
if (!hasPoints()) {
mPath.moveTo(mLastX = 0, mLastY = 0);
}
@@ -714,7 +714,7 @@
* @param x2 The x-coordinate of the end point on a quadratic curve
* @param y2 The y-coordinate of the end point on a quadratic curve
*/
- private void quadTo(float x1, float y1, float x2, float y2) {
+ public void quadTo(float x1, float y1, float x2, float y2) {
mPath.quadTo(x1, y1, mLastX = x2, mLastY = y2);
}
@@ -732,7 +732,7 @@
* @param dy2 The amount to add to the y-coordinate of the last point on
* this contour, for the end point of a quadratic curve
*/
- private void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
+ public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
if (!hasPoints()) {
mPath.moveTo(mLastX = 0, mLastY = 0);
}
@@ -755,7 +755,7 @@
* @param x3 The x-coordinate of the end point on a cubic curve
* @param y3 The y-coordinate of the end point on a cubic curve
*/
- private void cubicTo(float x1, float y1, float x2, float y2,
+ public void cubicTo(float x1, float y1, float x2, float y2,
float x3, float y3) {
if (!hasPoints()) {
mPath.moveTo(0, 0);
@@ -768,7 +768,7 @@
* current point on this contour. If there is no previous point, then a
* moveTo(0,0) is inserted automatically.
*/
- private void rCubicTo(float dx1, float dy1, float dx2, float dy2,
+ public void rCubicTo(float dx1, float dy1, float dx2, float dy2,
float dx3, float dy3) {
if (!hasPoints()) {
mPath.moveTo(mLastX = 0, mLastY = 0);
@@ -798,7 +798,7 @@
* mod 360.
* @param forceMoveTo If true, always begin a new contour with the arc
*/
- private void arcTo(float left, float top, float right, float bottom, float startAngle,
+ public void arcTo(float left, float top, float right, float bottom, float startAngle,
float sweepAngle,
boolean forceMoveTo) {
Arc2D arc = new Arc2D.Float(left, top, right - left, bottom - top, -startAngle,
@@ -812,7 +812,7 @@
* Close the current contour. If the current point is not equal to the
* first point of the contour, a line segment is automatically added.
*/
- private void close() {
+ public void close() {
mPath.closePath();
}
@@ -831,7 +831,7 @@
* @param bottom The bottom of a rectangle to add to the path
* @param dir The direction to wind the rectangle's contour
*/
- private void addRect(float left, float top, float right, float bottom,
+ public void addRect(float left, float top, float right, float bottom,
int dir) {
moveTo(left, top);
diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
new file mode 100644
index 0000000..eef8235
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
@@ -0,0 +1,1122 @@
+/*
+ * Copyright (C) 2016 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.graphics.drawable;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Canvas_Delegate;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Paint.Cap;
+import android.graphics.Paint.Join;
+import android.graphics.Paint_Delegate;
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+import android.graphics.Path_Delegate;
+import android.graphics.Rect;
+import android.graphics.Region.Op;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.MathUtils;
+import android.util.PathParser_Delegate;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.util.ArrayList;
+
+import static android.graphics.Canvas.CLIP_SAVE_FLAG;
+import static android.graphics.Canvas.MATRIX_SAVE_FLAG;
+import static android.graphics.Paint.Cap.BUTT;
+import static android.graphics.Paint.Cap.ROUND;
+import static android.graphics.Paint.Cap.SQUARE;
+import static android.graphics.Paint.Join.BEVEL;
+import static android.graphics.Paint.Join.MITER;
+import static android.graphics.Paint.Style;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link VectorDrawable}
+ * <p>
+ * Through the layoutlib_create tool, the original methods of VectorDrawable have been replaced by
+ * calls to methods of the same name in this delegate class.
+ */
+@SuppressWarnings("unused")
+public class VectorDrawable_Delegate {
+ private static final String LOGTAG = VectorDrawable_Delegate.class.getSimpleName();
+ private static final boolean DBG_VECTOR_DRAWABLE = false;
+
+ private static final DelegateManager<VNativeObject> sPathManager =
+ new DelegateManager<>(VNativeObject.class);
+
+ private static <T> T getDelegate(long nativePtr) {
+ //noinspection unchecked
+ T object = (T) sPathManager.getDelegate(nativePtr);
+ assert object != null;
+
+ return object;
+ }
+
+ /**
+ * Obtains styled attributes from the theme, if available, or unstyled resources if the theme is
+ * null.
+ */
+ private static TypedArray obtainAttributes(
+ Resources res, Theme theme, AttributeSet set, int[] attrs) {
+ if (theme == null) {
+ return res.obtainAttributes(set, attrs);
+ }
+ return theme.obtainStyledAttributes(set, attrs, 0, 0);
+ }
+
+ private static int applyAlpha(int color, float alpha) {
+ int alphaBytes = Color.alpha(color);
+ color &= 0x00FFFFFF;
+ color |= ((int) (alphaBytes * alpha)) << 24;
+ return color;
+ }
+
+ @LayoutlibDelegate
+ static long nCreateRenderer(long rootGroupPtr) {
+ VGroup_Delegate rootGroup = getDelegate(rootGroupPtr);
+ return sPathManager.addNewDelegate(new VPathRenderer_Delegate(rootGroup));
+ }
+
+ @LayoutlibDelegate
+ static void nSetRendererViewportSize(long rendererPtr, float viewportWidth,
+ float viewportHeight) {
+ VPathRenderer_Delegate nativePathRenderer = getDelegate(rendererPtr);
+ nativePathRenderer.mViewportWidth = viewportWidth;
+ nativePathRenderer.mViewportHeight = viewportHeight;
+ }
+
+ @LayoutlibDelegate
+ static boolean nSetRootAlpha(long rendererPtr, float alpha) {
+ VPathRenderer_Delegate nativePathRenderer = getDelegate(rendererPtr);
+ nativePathRenderer.setRootAlpha(alpha);
+
+ return true;
+ }
+
+ @LayoutlibDelegate
+ static float nGetRootAlpha(long rendererPtr) {
+ VPathRenderer_Delegate nativePathRenderer = getDelegate(rendererPtr);
+
+ return nativePathRenderer.getRootAlpha();
+ }
+
+ @LayoutlibDelegate
+ static void nSetAllowCaching(long rendererPtr, boolean allowCaching) {
+ // ignored
+ }
+
+ @LayoutlibDelegate
+ static void nDraw(long rendererPtr, long canvasWrapperPtr,
+ long colorFilterPtr, Rect bounds, boolean needsMirroring, boolean canReuseCache) {
+ VPathRenderer_Delegate nativePathRenderer =
+ getDelegate(rendererPtr);
+
+ Canvas_Delegate.native_save(canvasWrapperPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
+ Canvas_Delegate.native_translate(canvasWrapperPtr, bounds.left, bounds.top);
+
+ if (needsMirroring) {
+ Canvas_Delegate.native_translate(canvasWrapperPtr, bounds.width(), 0);
+ Canvas_Delegate.native_scale(canvasWrapperPtr, -1.0f, 1.0f);
+ }
+
+ // At this point, canvas has been translated to the right position.
+ // And we use this bound for the destination rect for the drawBitmap, so
+ // we offset to (0, 0);
+ bounds.offsetTo(0, 0);
+ nativePathRenderer.draw(canvasWrapperPtr, colorFilterPtr, bounds.width(), bounds.height());
+
+ Canvas_Delegate.native_restore(canvasWrapperPtr, true);
+ }
+
+ @LayoutlibDelegate
+ static long nCreateFullPath() {
+ return sPathManager.addNewDelegate(new VFullPath_Delegate());
+ }
+
+ @LayoutlibDelegate
+ static long nCreateFullPath(long nativeFullPathPtr) {
+ VFullPath_Delegate original = getDelegate(nativeFullPathPtr);
+
+ return sPathManager.addNewDelegate(new VFullPath_Delegate(original));
+ }
+
+ @LayoutlibDelegate
+ static boolean nGetFullPathProperties(long pathPtr, byte[] propertiesData,
+ int length) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+
+ ByteBuffer properties = ByteBuffer.wrap(propertiesData);
+ properties.order(ByteOrder.nativeOrder());
+
+ properties.putFloat(VFullPath_Delegate.STROKE_WIDTH_INDEX * 4, path.getStrokeWidth());
+ properties.putInt(VFullPath_Delegate.STROKE_COLOR_INDEX * 4, path.getStrokeColor());
+ properties.putFloat(VFullPath_Delegate.STROKE_ALPHA_INDEX * 4, path.getStrokeAlpha());
+ properties.putInt(VFullPath_Delegate.FILL_COLOR_INDEX * 4, path.getFillColor());
+ properties.putFloat(VFullPath_Delegate.FILL_ALPHA_INDEX * 4, path.getStrokeAlpha());
+ properties.putFloat(VFullPath_Delegate.TRIM_PATH_START_INDEX * 4, path.getTrimPathStart());
+ properties.putFloat(VFullPath_Delegate.TRIM_PATH_END_INDEX * 4, path.getTrimPathEnd());
+ properties.putFloat(VFullPath_Delegate.TRIM_PATH_OFFSET_INDEX * 4,
+ path.getTrimPathOffset());
+ properties.putInt(VFullPath_Delegate.STROKE_LINE_CAP_INDEX * 4, path.getStrokeLineCap());
+ properties.putInt(VFullPath_Delegate.STROKE_LINE_JOIN_INDEX * 4, path.getStrokeLineJoin());
+ properties.putFloat(VFullPath_Delegate.STROKE_MITER_LIMIT_INDEX * 4,
+ path.getStrokeMiterlimit());
+
+ return true;
+ }
+
+ @LayoutlibDelegate
+ static void nUpdateFullPathProperties(long pathPtr, float strokeWidth,
+ int strokeColor, float strokeAlpha, int fillColor, float fillAlpha, float trimPathStart,
+ float trimPathEnd, float trimPathOffset, float strokeMiterLimit, int strokeLineCap,
+ int strokeLineJoin) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+
+ path.setStrokeWidth(strokeWidth);
+ path.setStrokeColor(strokeColor);
+ path.setStrokeAlpha(strokeAlpha);
+ path.setFillColor(fillColor);
+ path.setFillAlpha(fillAlpha);
+ path.setTrimPathStart(trimPathStart);
+ path.setTrimPathEnd(trimPathEnd);
+ path.setTrimPathOffset(trimPathOffset);
+ path.setStrokeMiterlimit(strokeMiterLimit);
+ path.setStrokeLineCap(strokeLineCap);
+ path.setStrokeLineJoin(strokeLineJoin);
+ }
+
+ @LayoutlibDelegate
+ static void nUpdateFullPathFillGradient(long pathPtr, long fillGradientPtr) {
+
+ }
+
+ @LayoutlibDelegate
+ static void nUpdateFullPathStrokeGradient(long pathPtr, long strokeGradientPtr) {
+
+ }
+
+ @LayoutlibDelegate
+ static long nCreateClipPath() {
+ return sPathManager.addNewDelegate(new VClipPath_Delegate());
+ }
+
+ @LayoutlibDelegate
+ static long nCreateClipPath(long clipPathPtr) {
+ VClipPath_Delegate original = getDelegate(clipPathPtr);
+ return sPathManager.addNewDelegate(new VClipPath_Delegate(original));
+ }
+
+ @LayoutlibDelegate
+ static long nCreateGroup() {
+ return sPathManager.addNewDelegate(new VGroup_Delegate());
+ }
+
+ @LayoutlibDelegate
+ static long nCreateGroup(long groupPtr) {
+ VGroup_Delegate original = getDelegate(groupPtr);
+ return sPathManager.addNewDelegate(
+ new VGroup_Delegate(original, new ArrayMap<String, Object>()));
+ }
+
+ @LayoutlibDelegate
+ static void nSetName(long nodePtr, String name) {
+ VNativeObject group = getDelegate(nodePtr);
+ group.setName(name);
+ }
+
+ @LayoutlibDelegate
+ static boolean nGetGroupProperties(long groupPtr, float[] propertiesData,
+ int length) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+
+ FloatBuffer properties = FloatBuffer.wrap(propertiesData);
+
+ properties.put(VGroup_Delegate.ROTATE_INDEX, group.getRotation());
+ properties.put(VGroup_Delegate.PIVOT_X_INDEX, group.getPivotX());
+ properties.put(VGroup_Delegate.PIVOT_Y_INDEX, group.getPivotY());
+ properties.put(VGroup_Delegate.SCALE_X_INDEX, group.getScaleX());
+ properties.put(VGroup_Delegate.SCALE_Y_INDEX, group.getScaleY());
+ properties.put(VGroup_Delegate.TRANSLATE_X_INDEX, group.getTranslateX());
+ properties.put(VGroup_Delegate.TRANSLATE_Y_INDEX, group.getTranslateY());
+
+ return true;
+ }
+ @LayoutlibDelegate
+ static void nUpdateGroupProperties(long groupPtr, float rotate, float pivotX,
+ float pivotY, float scaleX, float scaleY, float translateX, float translateY) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+
+ group.setRotation(rotate);
+ group.setPivotX(pivotX);
+ group.setPivotY(pivotY);
+ group.setScaleX(scaleX);
+ group.setScaleY(scaleY);
+ group.setTranslateX(translateX);
+ group.setTranslateY(translateY);
+ }
+
+ @LayoutlibDelegate
+ static void nAddChild(long groupPtr, long nodePtr) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+ group.mChildren.add(getDelegate(nodePtr));
+ }
+
+ @LayoutlibDelegate
+ static void nSetPathString(long pathPtr, String pathString, int length) {
+ VPath_Delegate path = getDelegate(pathPtr);
+ path.setPathData(PathParser_Delegate.createNodesFromPathData(pathString));
+ }
+
+ /**
+ * The setters and getters below for paths and groups are here temporarily, and will be removed
+ * once the animation in AVD is replaced with RenderNodeAnimator, in which case the animation
+ * will modify these properties in native. By then no JNI hopping would be necessary for VD
+ * during animation, and these setters and getters will be obsolete.
+ */
+ // Setters and getters during animation.
+ @LayoutlibDelegate
+ static float nGetRotation(long groupPtr) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+ return group.getRotation();
+ }
+
+ @LayoutlibDelegate
+ static void nSetRotation(long groupPtr, float rotation) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+ group.setRotation(rotation);
+ }
+
+ @LayoutlibDelegate
+ static float nGetPivotX(long groupPtr) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+ return group.getPivotX();
+ }
+
+ @LayoutlibDelegate
+ static void nSetPivotX(long groupPtr, float pivotX) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+ group.setPivotX(pivotX);
+ }
+
+ @LayoutlibDelegate
+ static float nGetPivotY(long groupPtr) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+ return group.getPivotY();
+ }
+
+ @LayoutlibDelegate
+ static void nSetPivotY(long groupPtr, float pivotY) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+ group.setPivotY(pivotY);
+ }
+
+ @LayoutlibDelegate
+ static float nGetScaleX(long groupPtr) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+ return group.getScaleX();
+ }
+
+ @LayoutlibDelegate
+ static void nSetScaleX(long groupPtr, float scaleX) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+ group.setScaleX(scaleX);
+ }
+
+ @LayoutlibDelegate
+ static float nGetScaleY(long groupPtr) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+ return group.getScaleY();
+ }
+
+ @LayoutlibDelegate
+ static void nSetScaleY(long groupPtr, float scaleY) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+ group.setScaleY(scaleY);
+ }
+
+ @LayoutlibDelegate
+ static float nGetTranslateX(long groupPtr) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+ return group.getTranslateX();
+ }
+
+ @LayoutlibDelegate
+ static void nSetTranslateX(long groupPtr, float translateX) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+ group.setTranslateX(translateX);
+ }
+
+ @LayoutlibDelegate
+ static float nGetTranslateY(long groupPtr) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+ return group.getTranslateY();
+ }
+
+ @LayoutlibDelegate
+ static void nSetTranslateY(long groupPtr, float translateY) {
+ VGroup_Delegate group = getDelegate(groupPtr);
+ group.setTranslateY(translateY);
+ }
+
+ @LayoutlibDelegate
+ static void nSetPathData(long pathPtr, long pathDataPtr) {
+ VPath_Delegate path = getDelegate(pathPtr);
+ path.setPathData(PathParser_Delegate.getDelegate(pathDataPtr).getPathDataNodes());
+ }
+
+ @LayoutlibDelegate
+ static float nGetStrokeWidth(long pathPtr) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+ return path.getStrokeWidth();
+ }
+
+ @LayoutlibDelegate
+ static void nSetStrokeWidth(long pathPtr, float width) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+ path.setStrokeWidth(width);
+ }
+
+ @LayoutlibDelegate
+ static int nGetStrokeColor(long pathPtr) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+ return path.getStrokeColor();
+ }
+
+ @LayoutlibDelegate
+ static void nSetStrokeColor(long pathPtr, int strokeColor) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+ path.setStrokeColor(strokeColor);
+ }
+
+ @LayoutlibDelegate
+ static float nGetStrokeAlpha(long pathPtr) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+ return path.getStrokeAlpha();
+ }
+
+ @LayoutlibDelegate
+ static void nSetStrokeAlpha(long pathPtr, float alpha) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+ path.setStrokeAlpha(alpha);
+ }
+
+ @LayoutlibDelegate
+ static int nGetFillColor(long pathPtr) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+ return path.getFillColor();
+ }
+
+ @LayoutlibDelegate
+ static void nSetFillColor(long pathPtr, int fillColor) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+ path.setFillColor(fillColor);
+ }
+
+ @LayoutlibDelegate
+ static float nGetFillAlpha(long pathPtr) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+ return path.getFillAlpha();
+ }
+
+ @LayoutlibDelegate
+ static void nSetFillAlpha(long pathPtr, float fillAlpha) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+ path.setFillAlpha(fillAlpha);
+ }
+
+ @LayoutlibDelegate
+ static float nGetTrimPathStart(long pathPtr) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+ return path.getTrimPathStart();
+ }
+
+ @LayoutlibDelegate
+ static void nSetTrimPathStart(long pathPtr, float trimPathStart) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+ path.setTrimPathStart(trimPathStart);
+ }
+
+ @LayoutlibDelegate
+ static float nGetTrimPathEnd(long pathPtr) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+ return path.getTrimPathEnd();
+ }
+
+ @LayoutlibDelegate
+ static void nSetTrimPathEnd(long pathPtr, float trimPathEnd) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+ path.setTrimPathEnd(trimPathEnd);
+ }
+
+ @LayoutlibDelegate
+ static float nGetTrimPathOffset(long pathPtr) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+ return path.getTrimPathOffset();
+ }
+
+ @LayoutlibDelegate
+ static void nSetTrimPathOffset(long pathPtr, float trimPathOffset) {
+ VFullPath_Delegate path = getDelegate(pathPtr);
+ path.setTrimPathOffset(trimPathOffset);
+ }
+
+ /**
+ * Base class for all the internal Delegates that does two functions:
+ * <ol>
+ * <li>Serves as base class to store all the delegates in one {@link DelegateManager}
+ * <li>Provides setName for all the classes. {@link VPathRenderer_Delegate} does actually
+ * not need it
+ * </ol>
+ */
+ private interface VNativeObject {
+ void setName(String name);
+ }
+
+ private static class VClipPath_Delegate extends VPath_Delegate {
+ private VClipPath_Delegate() {
+ // Empty constructor.
+ }
+
+ private VClipPath_Delegate(VClipPath_Delegate copy) {
+ super(copy);
+ }
+
+ @Override
+ public boolean isClipPath() {
+ return true;
+ }
+ }
+
+ private static class VFullPath_Delegate extends VPath_Delegate {
+ // These constants need to be kept in sync with their values in VectorDrawable.VFullPath
+ private static final int STROKE_WIDTH_INDEX = 0;
+ private static final int STROKE_COLOR_INDEX = 1;
+ private static final int STROKE_ALPHA_INDEX = 2;
+ private static final int FILL_COLOR_INDEX = 3;
+ private static final int FILL_ALPHA_INDEX = 4;
+ private static final int TRIM_PATH_START_INDEX = 5;
+ private static final int TRIM_PATH_END_INDEX = 6;
+ private static final int TRIM_PATH_OFFSET_INDEX = 7;
+ private static final int STROKE_LINE_CAP_INDEX = 8;
+ private static final int STROKE_LINE_JOIN_INDEX = 9;
+ private static final int STROKE_MITER_LIMIT_INDEX = 10;
+
+ private static final int LINECAP_BUTT = 0;
+ private static final int LINECAP_ROUND = 1;
+ private static final int LINECAP_SQUARE = 2;
+
+ private static final int LINEJOIN_MITER = 0;
+ private static final int LINEJOIN_ROUND = 1;
+ private static final int LINEJOIN_BEVEL = 2;
+
+ /////////////////////////////////////////////////////
+ // Variables below need to be copied (deep copy if applicable) for mutation.
+
+ int mStrokeColor = Color.TRANSPARENT;
+ float mStrokeWidth = 0;
+
+ int mFillColor = Color.TRANSPARENT;
+ float mStrokeAlpha = 1.0f;
+ float mFillAlpha = 1.0f;
+ float mTrimPathStart = 0;
+ float mTrimPathEnd = 1;
+ float mTrimPathOffset = 0;
+
+ Cap mStrokeLineCap = BUTT;
+ Join mStrokeLineJoin = MITER;
+ float mStrokeMiterlimit = 4;
+
+ private VFullPath_Delegate() {
+ // Empty constructor.
+ }
+
+ private VFullPath_Delegate(VFullPath_Delegate copy) {
+ super(copy);
+
+ mStrokeColor = copy.mStrokeColor;
+ mStrokeWidth = copy.mStrokeWidth;
+ mStrokeAlpha = copy.mStrokeAlpha;
+ mFillColor = copy.mFillColor;
+ mFillAlpha = copy.mFillAlpha;
+ mTrimPathStart = copy.mTrimPathStart;
+ mTrimPathEnd = copy.mTrimPathEnd;
+ mTrimPathOffset = copy.mTrimPathOffset;
+
+ mStrokeLineCap = copy.mStrokeLineCap;
+ mStrokeLineJoin = copy.mStrokeLineJoin;
+ mStrokeMiterlimit = copy.mStrokeMiterlimit;
+ }
+
+ private int getStrokeLineCap() {
+ switch (mStrokeLineCap) {
+ case BUTT:
+ return LINECAP_BUTT;
+ case ROUND:
+ return LINECAP_ROUND;
+ case SQUARE:
+ return LINECAP_SQUARE;
+ default:
+ assert false;
+ }
+
+ return -1;
+ }
+
+ private void setStrokeLineCap(int cap) {
+ switch (cap) {
+ case LINECAP_BUTT:
+ mStrokeLineCap = BUTT;
+ break;
+ case LINECAP_ROUND:
+ mStrokeLineCap = ROUND;
+ break;
+ case LINECAP_SQUARE:
+ mStrokeLineCap = SQUARE;
+ break;
+ default:
+ assert false;
+ }
+ }
+
+ private int getStrokeLineJoin() {
+ switch (mStrokeLineJoin) {
+ case MITER:
+ return LINEJOIN_MITER;
+ case ROUND:
+ return LINEJOIN_ROUND;
+ case BEVEL:
+ return LINEJOIN_BEVEL;
+ default:
+ assert false;
+ }
+
+ return -1;
+ }
+
+ private void setStrokeLineJoin(int join) {
+ switch (join) {
+ case LINEJOIN_BEVEL:
+ mStrokeLineJoin = BEVEL;
+ break;
+ case LINEJOIN_MITER:
+ mStrokeLineJoin = MITER;
+ break;
+ case LINEJOIN_ROUND:
+ mStrokeLineJoin = Join.ROUND;
+ break;
+ default:
+ assert false;
+ }
+ }
+
+ private int getStrokeColor() {
+ return mStrokeColor;
+ }
+
+ private void setStrokeColor(int strokeColor) {
+ mStrokeColor = strokeColor;
+ }
+
+ private float getStrokeWidth() {
+ return mStrokeWidth;
+ }
+
+ private void setStrokeWidth(float strokeWidth) {
+ mStrokeWidth = strokeWidth;
+ }
+
+ private float getStrokeAlpha() {
+ return mStrokeAlpha;
+ }
+
+ private void setStrokeAlpha(float strokeAlpha) {
+ mStrokeAlpha = strokeAlpha;
+ }
+
+ private int getFillColor() {
+ return mFillColor;
+ }
+
+ private void setFillColor(int fillColor) {
+ mFillColor = fillColor;
+ }
+
+ private float getFillAlpha() {
+ return mFillAlpha;
+ }
+
+ private void setFillAlpha(float fillAlpha) {
+ mFillAlpha = fillAlpha;
+ }
+
+ private float getTrimPathStart() {
+ return mTrimPathStart;
+ }
+
+ private void setTrimPathStart(float trimPathStart) {
+ mTrimPathStart = trimPathStart;
+ }
+
+ private float getTrimPathEnd() {
+ return mTrimPathEnd;
+ }
+
+ private void setTrimPathEnd(float trimPathEnd) {
+ mTrimPathEnd = trimPathEnd;
+ }
+
+ private float getTrimPathOffset() {
+ return mTrimPathOffset;
+ }
+
+ private void setTrimPathOffset(float trimPathOffset) {
+ mTrimPathOffset = trimPathOffset;
+ }
+
+ private void setStrokeMiterlimit(float limit) {
+ mStrokeMiterlimit = limit;
+ }
+
+ private float getStrokeMiterlimit() {
+ return mStrokeMiterlimit;
+ }
+ }
+
+ private static class VGroup_Delegate implements VNativeObject {
+ // This constants need to be kept in sync with their definitions in VectorDrawable.Group
+ private static final int ROTATE_INDEX = 0;
+ private static final int PIVOT_X_INDEX = 1;
+ private static final int PIVOT_Y_INDEX = 2;
+ private static final int SCALE_X_INDEX = 3;
+ private static final int SCALE_Y_INDEX = 4;
+ private static final int TRANSLATE_X_INDEX = 5;
+ private static final int TRANSLATE_Y_INDEX = 6;
+
+ /////////////////////////////////////////////////////
+ // Variables below need to be copied (deep copy if applicable) for mutation.
+ final ArrayList<Object> mChildren = new ArrayList<>();
+ // mStackedMatrix is only used temporarily when drawing, it combines all
+ // the parents' local matrices with the current one.
+ private final Matrix mStackedMatrix = new Matrix();
+ // mLocalMatrix is updated based on the update of transformation information,
+ // either parsed from the XML or by animation.
+ private final Matrix mLocalMatrix = new Matrix();
+ private float mRotate = 0;
+ private float mPivotX = 0;
+ private float mPivotY = 0;
+ private float mScaleX = 1;
+ private float mScaleY = 1;
+ private float mTranslateX = 0;
+ private float mTranslateY = 0;
+ private int mChangingConfigurations;
+ private String mGroupName = null;
+
+ private VGroup_Delegate(VGroup_Delegate copy, ArrayMap<String, Object> targetsMap) {
+ mRotate = copy.mRotate;
+ mPivotX = copy.mPivotX;
+ mPivotY = copy.mPivotY;
+ mScaleX = copy.mScaleX;
+ mScaleY = copy.mScaleY;
+ mTranslateX = copy.mTranslateX;
+ mTranslateY = copy.mTranslateY;
+ mGroupName = copy.mGroupName;
+ mChangingConfigurations = copy.mChangingConfigurations;
+ if (mGroupName != null) {
+ targetsMap.put(mGroupName, this);
+ }
+
+ mLocalMatrix.set(copy.mLocalMatrix);
+
+ final ArrayList<Object> children = copy.mChildren;
+ //noinspection ForLoopReplaceableByForEach
+ for (int i = 0; i < children.size(); i++) {
+ Object copyChild = children.get(i);
+ if (copyChild instanceof VGroup_Delegate) {
+ VGroup_Delegate copyGroup = (VGroup_Delegate) copyChild;
+ mChildren.add(new VGroup_Delegate(copyGroup, targetsMap));
+ } else {
+ VPath_Delegate newPath;
+ if (copyChild instanceof VFullPath_Delegate) {
+ newPath = new VFullPath_Delegate((VFullPath_Delegate) copyChild);
+ } else if (copyChild instanceof VClipPath_Delegate) {
+ newPath = new VClipPath_Delegate((VClipPath_Delegate) copyChild);
+ } else {
+ throw new IllegalStateException("Unknown object in the tree!");
+ }
+ mChildren.add(newPath);
+ if (newPath.mPathName != null) {
+ targetsMap.put(newPath.mPathName, newPath);
+ }
+ }
+ }
+ }
+
+ private VGroup_Delegate() {
+ }
+
+ private void updateLocalMatrix() {
+ // The order we apply is the same as the
+ // RenderNode.cpp::applyViewPropertyTransforms().
+ mLocalMatrix.reset();
+ mLocalMatrix.postTranslate(-mPivotX, -mPivotY);
+ mLocalMatrix.postScale(mScaleX, mScaleY);
+ mLocalMatrix.postRotate(mRotate, 0, 0);
+ mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
+ }
+
+ /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
+ private float getRotation() {
+ return mRotate;
+ }
+
+ private void setRotation(float rotation) {
+ if (rotation != mRotate) {
+ mRotate = rotation;
+ updateLocalMatrix();
+ }
+ }
+
+ private float getPivotX() {
+ return mPivotX;
+ }
+
+ private void setPivotX(float pivotX) {
+ if (pivotX != mPivotX) {
+ mPivotX = pivotX;
+ updateLocalMatrix();
+ }
+ }
+
+ private float getPivotY() {
+ return mPivotY;
+ }
+
+ private void setPivotY(float pivotY) {
+ if (pivotY != mPivotY) {
+ mPivotY = pivotY;
+ updateLocalMatrix();
+ }
+ }
+
+ private float getScaleX() {
+ return mScaleX;
+ }
+
+ private void setScaleX(float scaleX) {
+ if (scaleX != mScaleX) {
+ mScaleX = scaleX;
+ updateLocalMatrix();
+ }
+ }
+
+ private float getScaleY() {
+ return mScaleY;
+ }
+
+ private void setScaleY(float scaleY) {
+ if (scaleY != mScaleY) {
+ mScaleY = scaleY;
+ updateLocalMatrix();
+ }
+ }
+
+ private float getTranslateX() {
+ return mTranslateX;
+ }
+
+ private void setTranslateX(float translateX) {
+ if (translateX != mTranslateX) {
+ mTranslateX = translateX;
+ updateLocalMatrix();
+ }
+ }
+
+ private float getTranslateY() {
+ return mTranslateY;
+ }
+
+ private void setTranslateY(float translateY) {
+ if (translateY != mTranslateY) {
+ mTranslateY = translateY;
+ updateLocalMatrix();
+ }
+ }
+
+ @Override
+ public void setName(String name) {
+ mGroupName = name;
+ }
+ }
+
+ public static class VPath_Delegate implements VNativeObject {
+ protected PathParser_Delegate.PathDataNode[] mNodes = null;
+ String mPathName;
+ int mChangingConfigurations;
+
+ public VPath_Delegate() {
+ // Empty constructor.
+ }
+
+ public VPath_Delegate(VPath_Delegate copy) {
+ mPathName = copy.mPathName;
+ mChangingConfigurations = copy.mChangingConfigurations;
+ mNodes = PathParser_Delegate.deepCopyNodes(copy.mNodes);
+ }
+
+ public void toPath(Path path) {
+ path.reset();
+ if (mNodes != null) {
+ PathParser_Delegate.PathDataNode.nodesToPath(mNodes,
+ Path_Delegate.getDelegate(path.mNativePath));
+ }
+ }
+
+ @Override
+ public void setName(String name) {
+ mPathName = name;
+ }
+
+ public boolean isClipPath() {
+ return false;
+ }
+
+ private void setPathData(PathParser_Delegate.PathDataNode[] nodes) {
+ if (!PathParser_Delegate.canMorph(mNodes, nodes)) {
+ // This should not happen in the middle of animation.
+ mNodes = PathParser_Delegate.deepCopyNodes(nodes);
+ } else {
+ PathParser_Delegate.updateNodes(mNodes, nodes);
+ }
+ }
+ }
+
+ private static class VPathRenderer_Delegate implements VNativeObject {
+ /* Right now the internal data structure is organized as a tree.
+ * Each node can be a group node, or a path.
+ * A group node can have groups or paths as children, but a path node has
+ * no children.
+ * One example can be:
+ * Root Group
+ * / | \
+ * Group Path Group
+ * / \ |
+ * Path Path Path
+ *
+ */
+ // Variables that only used temporarily inside the draw() call, so there
+ // is no need for deep copying.
+ private final Path mPath;
+ private final Path mRenderPath;
+ private final Matrix mFinalPathMatrix = new Matrix();
+ private final VGroup_Delegate mRootGroup;
+ private float mViewportWidth = 0;
+ private float mViewportHeight = 0;
+ private float mRootAlpha = 1.0f;
+ private Paint mStrokePaint;
+ private Paint mFillPaint;
+ private PathMeasure mPathMeasure;
+
+ private VPathRenderer_Delegate(VGroup_Delegate rootGroup) {
+ mRootGroup = rootGroup;
+ mPath = new Path();
+ mRenderPath = new Path();
+ }
+
+ private float getRootAlpha() {
+ return mRootAlpha;
+ }
+
+ private void setRootAlpha(float alpha) {
+ mRootAlpha = alpha;
+ }
+
+ private void drawGroupTree(VGroup_Delegate currentGroup, Matrix currentMatrix,
+ long canvasPtr, int w, int h, long filterPtr) {
+ // Calculate current group's matrix by preConcat the parent's and
+ // and the current one on the top of the stack.
+ // Basically the Mfinal = Mviewport * M0 * M1 * M2;
+ // Mi the local matrix at level i of the group tree.
+ currentGroup.mStackedMatrix.set(currentMatrix);
+ currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix);
+
+ // Save the current clip information, which is local to this group.
+ Canvas_Delegate.native_save(canvasPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
+ // Draw the group tree in the same order as the XML file.
+ for (int i = 0; i < currentGroup.mChildren.size(); i++) {
+ Object child = currentGroup.mChildren.get(i);
+ if (child instanceof VGroup_Delegate) {
+ VGroup_Delegate childGroup = (VGroup_Delegate) child;
+ drawGroupTree(childGroup, currentGroup.mStackedMatrix,
+ canvasPtr, w, h, filterPtr);
+ } else if (child instanceof VPath_Delegate) {
+ VPath_Delegate childPath = (VPath_Delegate) child;
+ drawPath(currentGroup, childPath, canvasPtr, w, h, filterPtr);
+ }
+ }
+ Canvas_Delegate.native_restore(canvasPtr, true);
+ }
+
+ public void draw(long canvasPtr, long filterPtr, int w, int h) {
+ // Traverse the tree in pre-order to draw.
+ drawGroupTree(mRootGroup, Matrix.IDENTITY_MATRIX, canvasPtr, w, h, filterPtr);
+ }
+
+ private void drawPath(VGroup_Delegate VGroup, VPath_Delegate VPath, long canvasPtr,
+ int w,
+ int h,
+ long filterPtr) {
+ final float scaleX = w / mViewportWidth;
+ final float scaleY = h / mViewportHeight;
+ final float minScale = Math.min(scaleX, scaleY);
+ final Matrix groupStackedMatrix = VGroup.mStackedMatrix;
+
+ mFinalPathMatrix.set(groupStackedMatrix);
+ mFinalPathMatrix.postScale(scaleX, scaleY);
+
+ final float matrixScale = getMatrixScale(groupStackedMatrix);
+ if (matrixScale == 0) {
+ // When either x or y is scaled to 0, we don't need to draw anything.
+ return;
+ }
+ VPath.toPath(mPath);
+ final Path path = mPath;
+
+ mRenderPath.reset();
+
+ if (VPath.isClipPath()) {
+ mRenderPath.addPath(path, mFinalPathMatrix);
+ Canvas_Delegate.native_clipPath(canvasPtr, mRenderPath.mNativePath, Op
+ .INTERSECT.nativeInt);
+ } else {
+ VFullPath_Delegate fullPath = (VFullPath_Delegate) VPath;
+ if (fullPath.mTrimPathStart != 0.0f || fullPath.mTrimPathEnd != 1.0f) {
+ float start = (fullPath.mTrimPathStart + fullPath.mTrimPathOffset) % 1.0f;
+ float end = (fullPath.mTrimPathEnd + fullPath.mTrimPathOffset) % 1.0f;
+
+ if (mPathMeasure == null) {
+ mPathMeasure = new PathMeasure();
+ }
+ mPathMeasure.setPath(mPath, false);
+
+ float len = mPathMeasure.getLength();
+ start = start * len;
+ end = end * len;
+ path.reset();
+ if (start > end) {
+ mPathMeasure.getSegment(start, len, path, true);
+ mPathMeasure.getSegment(0f, end, path, true);
+ } else {
+ mPathMeasure.getSegment(start, end, path, true);
+ }
+ path.rLineTo(0, 0); // fix bug in measure
+ }
+ mRenderPath.addPath(path, mFinalPathMatrix);
+
+ if (fullPath.mFillColor != Color.TRANSPARENT) {
+ if (mFillPaint == null) {
+ mFillPaint = new Paint();
+ mFillPaint.setStyle(Style.FILL);
+ mFillPaint.setAntiAlias(true);
+ }
+
+ final Paint fillPaint = mFillPaint;
+ fillPaint.setColor(applyAlpha(fullPath.mFillColor, fullPath.mFillAlpha));
+ Paint_Delegate fillPaintDelegate = Paint_Delegate.getDelegate(fillPaint
+ .getNativeInstance
+ ());
+ // mFillPaint can not be null at this point so we will have a delegate
+ assert fillPaintDelegate != null;
+ fillPaintDelegate.setColorFilter(filterPtr);
+ Canvas_Delegate.native_drawPath(canvasPtr, mRenderPath.mNativePath, fillPaint
+ .getNativeInstance());
+ }
+
+ if (fullPath.mStrokeColor != Color.TRANSPARENT) {
+ if (mStrokePaint == null) {
+ mStrokePaint = new Paint();
+ mStrokePaint.setStyle(Style.STROKE);
+ mStrokePaint.setAntiAlias(true);
+ }
+
+ final Paint strokePaint = mStrokePaint;
+ if (fullPath.mStrokeLineJoin != null) {
+ strokePaint.setStrokeJoin(fullPath.mStrokeLineJoin);
+ }
+
+ if (fullPath.mStrokeLineCap != null) {
+ strokePaint.setStrokeCap(fullPath.mStrokeLineCap);
+ }
+
+ strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit);
+ strokePaint.setColor(applyAlpha(fullPath.mStrokeColor, fullPath.mStrokeAlpha));
+ Paint_Delegate strokePaintDelegate = Paint_Delegate.getDelegate(strokePaint
+ .getNativeInstance());
+ // mStrokePaint can not be null at this point so we will have a delegate
+ assert strokePaintDelegate != null;
+ strokePaintDelegate.setColorFilter(filterPtr);
+ final float finalStrokeScale = minScale * matrixScale;
+ strokePaint.setStrokeWidth(fullPath.mStrokeWidth * finalStrokeScale);
+ Canvas_Delegate.native_drawPath(canvasPtr, mRenderPath.mNativePath, strokePaint
+ .getNativeInstance());
+ }
+ }
+ }
+
+ private float getMatrixScale(Matrix groupStackedMatrix) {
+ // Given unit vectors A = (0, 1) and B = (1, 0).
+ // After matrix mapping, we got A' and B'. Let theta = the angel b/t A' and B'.
+ // Therefore, the final scale we want is min(|A'| * sin(theta), |B'| * sin(theta)),
+ // which is (|A'| * |B'| * sin(theta)) / max (|A'|, |B'|);
+ // If max (|A'|, |B'|) = 0, that means either x or y has a scale of 0.
+ //
+ // For non-skew case, which is most of the cases, matrix scale is computing exactly the
+ // scale on x and y axis, and take the minimal of these two.
+ // For skew case, an unit square will mapped to a parallelogram. And this function will
+ // return the minimal height of the 2 bases.
+ float[] unitVectors = new float[]{0, 1, 1, 0};
+ groupStackedMatrix.mapVectors(unitVectors);
+ float scaleX = MathUtils.mag(unitVectors[0], unitVectors[1]);
+ float scaleY = MathUtils.mag(unitVectors[2], unitVectors[3]);
+ float crossProduct = MathUtils.cross(unitVectors[0], unitVectors[1],
+ unitVectors[2], unitVectors[3]);
+ float maxScale = MathUtils.max(scaleX, scaleY);
+
+ float matrixScale = 0;
+ if (maxScale > 0) {
+ matrixScale = MathUtils.abs(crossProduct) / maxScale;
+ }
+ if (DBG_VECTOR_DRAWABLE) {
+ Log.d(LOGTAG, "Scale x " + scaleX + " y " + scaleY + " final " + matrixScale);
+ }
+ return matrixScale;
+ }
+
+ @Override
+ public void setName(String name) {
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java b/tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java
index d3af837..6c34c70 100644
--- a/tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java
@@ -24,7 +24,6 @@
import android.annotation.NonNull;
import android.graphics.Path_Delegate;
-import java.awt.geom.Path2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Level;
@@ -52,10 +51,18 @@
@NonNull
private PathDataNode[] mPathDataNodes;
+ public static PathParser_Delegate getDelegate(long nativePtr) {
+ return sManager.getDelegate(nativePtr);
+ }
+
private PathParser_Delegate(@NonNull PathDataNode[] nodes) {
mPathDataNodes = nodes;
}
+ public PathDataNode[] getPathDataNodes() {
+ return mPathDataNodes;
+ }
+
@LayoutlibDelegate
/*package*/ static boolean nParseStringForPath(long pathPtr, @NonNull String pathString, int
stringLength) {
@@ -64,7 +71,7 @@
return false;
}
assert pathString.length() == stringLength;
- PathDataNode.nodesToPath(createNodesFromPathData(pathString), path_delegate.getJavaShape());
+ PathDataNode.nodesToPath(createNodesFromPathData(pathString), path_delegate);
return true;
}
@@ -75,7 +82,7 @@
if (source == null || path_delegate == null) {
return;
}
- PathDataNode.nodesToPath(source.mPathDataNodes, path_delegate.getJavaShape());
+ PathDataNode.nodesToPath(source.mPathDataNodes, path_delegate);
}
@LayoutlibDelegate
@@ -124,8 +131,11 @@
out.mPathDataNodes = new PathDataNode[length];
}
for (int i = 0; i < length; i++) {
+ if (out.mPathDataNodes[i] == null) {
+ out.mPathDataNodes[i] = new PathDataNode(from.mPathDataNodes[i]);
+ }
out.mPathDataNodes[i].interpolatePathDataNode(from.mPathDataNodes[i],
- to.mPathDataNodes[i], fraction);
+ to.mPathDataNodes[i], fraction);
}
return true;
}
@@ -137,9 +147,13 @@
@LayoutlibDelegate
/*package*/ static boolean nCanMorph(long fromDataPtr, long toDataPtr) {
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, "morphing path data isn't " +
- "supported", null, null);
- return false;
+ PathParser_Delegate fromPath = PathParser_Delegate.getDelegate(fromDataPtr);
+ PathParser_Delegate toPath = PathParser_Delegate.getDelegate(toDataPtr);
+ if (fromPath == null || toPath == null || fromPath.getPathDataNodes() == null || toPath
+ .getPathDataNodes() == null) {
+ return true;
+ }
+ return PathParser_Delegate.canMorph(fromPath.getPathDataNodes(), toPath.getPathDataNodes());
}
@LayoutlibDelegate
@@ -158,7 +172,7 @@
* @return an array of the PathDataNode.
*/
@NonNull
- private static PathDataNode[] createNodesFromPathData(@NonNull String pathData) {
+ public static PathDataNode[] createNodesFromPathData(@NonNull String pathData) {
int start = 0;
int end = 1;
@@ -186,7 +200,7 @@
* @return a deep copy of the <code>source</code>.
*/
@NonNull
- private static PathDataNode[] deepCopyNodes(@NonNull PathDataNode[] source) {
+ public static PathDataNode[] deepCopyNodes(@NonNull PathDataNode[] source) {
PathDataNode[] copy = new PathDataNode[source.length];
for (int i = 0; i < source.length; i++) {
copy[i] = new PathDataNode(source[i]);
@@ -194,6 +208,45 @@
return copy;
}
+ /**
+ * @param nodesFrom The source path represented in an array of PathDataNode
+ * @param nodesTo The target path represented in an array of PathDataNode
+ * @return whether the <code>nodesFrom</code> can morph into <code>nodesTo</code>
+ */
+ public static boolean canMorph(PathDataNode[] nodesFrom, PathDataNode[] nodesTo) {
+ if (nodesFrom == null || nodesTo == null) {
+ return false;
+ }
+
+ if (nodesFrom.length != nodesTo.length) {
+ return false;
+ }
+
+ for (int i = 0; i < nodesFrom.length; i ++) {
+ if (nodesFrom[i].mType != nodesTo[i].mType
+ || nodesFrom[i].mParams.length != nodesTo[i].mParams.length) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Update the target's data to match the source.
+ * Before calling this, make sure canMorph(target, source) is true.
+ *
+ * @param target The target path represented in an array of PathDataNode
+ * @param source The source path represented in an array of PathDataNode
+ */
+ public static void updateNodes(PathDataNode[] target, PathDataNode[] source) {
+ for (int i = 0; i < source.length; i ++) {
+ target[i].mType = source[i].mType;
+ for (int j = 0; j < source[i].mParams.length; j ++) {
+ target[i].mParams[j] = source[i].mParams[j];
+ }
+ }
+ }
+
private static int nextStart(@NonNull String s, int end) {
char c;
@@ -330,7 +383,7 @@
* Each PathDataNode represents one command in the "d" attribute of the svg file. An array of
* PathDataNode can represent the whole "d" attribute.
*/
- private static class PathDataNode {
+ public static class PathDataNode {
private char mType;
@NonNull
private float[] mParams;
@@ -355,12 +408,13 @@
}
/**
- * Convert an array of PathDataNode to Path.
+ * Convert an array of PathDataNode to Path. Reset the passed path as needed before
+ * calling this method.
*
* @param node The source array of PathDataNode.
* @param path The target Path object.
*/
- private static void nodesToPath(@NonNull PathDataNode[] node, @NonNull Path2D path) {
+ public static void nodesToPath(@NonNull PathDataNode[] node, @NonNull Path_Delegate path) {
float[] current = new float[6];
char previousCommand = 'm';
//noinspection ForLoopReplaceableByForEach
@@ -387,24 +441,32 @@
}
@SuppressWarnings("PointlessArithmeticExpression")
- private static void addCommand(@NonNull Path2D path, float[] current, char cmd,
- char lastCmd, @NonNull float[] val) {
+ private static void addCommand(@NonNull Path_Delegate path, float[] current,
+ char previousCmd, char cmd, @NonNull float[] val) {
int incr = 2;
-
- float cx = current[0];
- float cy = current[1];
- float cpx = current[2];
- float cpy = current[3];
- float loopX = current[4];
- float loopY = current[5];
+ float currentX = current[0];
+ float currentY = current[1];
+ float ctrlPointX = current[2];
+ float ctrlPointY = current[3];
+ float currentSegmentStartX = current[4];
+ float currentSegmentStartY = current[5];
+ float reflectiveCtrlPointX;
+ float reflectiveCtrlPointY;
switch (cmd) {
case 'z':
case 'Z':
- path.closePath();
- cx = loopX;
- cy = loopY;
+ path.close();
+ // Path is closed here, but we need to move the pen to the
+ // closed position. So we cache the segment's starting position,
+ // and restore it here.
+ currentX = currentSegmentStartX;
+ currentY = currentSegmentStartY;
+ ctrlPointX = currentSegmentStartX;
+ ctrlPointY = currentSegmentStartY;
+ path.moveTo(currentX, currentY);
+ break;
case 'm':
case 'M':
case 'l':
@@ -432,185 +494,206 @@
case 'a':
case 'A':
incr = 7;
+ break;
}
for (int k = 0; k < val.length; k += incr) {
- boolean reflectCtrl;
- float tempReflectedX, tempReflectedY;
-
switch (cmd) {
- case 'm':
- cx += val[k + 0];
- cy += val[k + 1];
+ case 'm': // moveto - Start a new sub-path (relative)
+ currentX += val[k + 0];
+ currentY += val[k + 1];
+
if (k > 0) {
// According to the spec, if a moveto is followed by multiple
// pairs of coordinates, the subsequent pairs are treated as
// implicit lineto commands.
- path.lineTo(cx, cy);
+ path.rLineTo(val[k + 0], val[k + 1]);
} else {
- path.moveTo(cx, cy);
- loopX = cx;
- loopY = cy;
+ path.rMoveTo(val[k + 0], val[k + 1]);
+ currentSegmentStartX = currentX;
+ currentSegmentStartY = currentY;
}
break;
- case 'M':
- cx = val[k + 0];
- cy = val[k + 1];
+ case 'M': // moveto - Start a new sub-path
+ currentX = val[k + 0];
+ currentY = val[k + 1];
+
if (k > 0) {
// According to the spec, if a moveto is followed by multiple
// pairs of coordinates, the subsequent pairs are treated as
// implicit lineto commands.
- path.lineTo(cx, cy);
+ path.lineTo(val[k + 0], val[k + 1]);
} else {
- path.moveTo(cx, cy);
- loopX = cx;
- loopY = cy;
+ path.moveTo(val[k + 0], val[k + 1]);
+ currentSegmentStartX = currentX;
+ currentSegmentStartY = currentY;
}
break;
- case 'l':
- cx += val[k + 0];
- cy += val[k + 1];
- path.lineTo(cx, cy);
+ case 'l': // lineto - Draw a line from the current point (relative)
+ path.rLineTo(val[k + 0], val[k + 1]);
+ currentX += val[k + 0];
+ currentY += val[k + 1];
break;
- case 'L':
- cx = val[k + 0];
- cy = val[k + 1];
- path.lineTo(cx, cy);
+ case 'L': // lineto - Draw a line from the current point
+ path.lineTo(val[k + 0], val[k + 1]);
+ currentX = val[k + 0];
+ currentY = val[k + 1];
break;
- case 'z':
- case 'Z':
- path.closePath();
- cx = loopX;
- cy = loopY;
+ case 'h': // horizontal lineto - Draws a horizontal line (relative)
+ path.rLineTo(val[k + 0], 0);
+ currentX += val[k + 0];
break;
- case 'h':
- cx += val[k + 0];
- path.lineTo(cx, cy);
+ case 'H': // horizontal lineto - Draws a horizontal line
+ path.lineTo(val[k + 0], currentY);
+ currentX = val[k + 0];
break;
- case 'H':
- path.lineTo(val[k + 0], cy);
- cx = val[k + 0];
+ case 'v': // vertical lineto - Draws a vertical line from the current point (r)
+ path.rLineTo(0, val[k + 0]);
+ currentY += val[k + 0];
break;
- case 'v':
- cy += val[k + 0];
- path.lineTo(cx, cy);
+ case 'V': // vertical lineto - Draws a vertical line from the current point
+ path.lineTo(currentX, val[k + 0]);
+ currentY = val[k + 0];
break;
- case 'V':
- path.lineTo(cx, val[k + 0]);
- cy = val[k + 0];
- break;
- case 'c':
- path.curveTo(cx + val[k + 0], cy + val[k + 1], cx + val[k + 2],
- cy + val[k + 3], cx + val[k + 4], cy + val[k + 5]);
- cpx = cx + val[k + 2];
- cpy = cy + val[k + 3];
- cx += val[k + 4];
- cy += val[k + 5];
- break;
- case 'C':
- path.curveTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
+ case 'c': // curveto - Draws a cubic Bézier curve (relative)
+ path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
val[k + 4], val[k + 5]);
- cx = val[k + 4];
- cy = val[k + 5];
- cpx = val[k + 2];
- cpy = val[k + 3];
- break;
- case 's':
- reflectCtrl = (lastCmd == 'c' || lastCmd == 's' || lastCmd == 'C' ||
- lastCmd == 'S');
- path.curveTo(reflectCtrl ? 2 * cx - cpx : cx, reflectCtrl ? 2
- * cy - cpy : cy, cx + val[k + 0], cy + val[k + 1], cx
- + val[k + 2], cy + val[k + 3]);
- cpx = cx + val[k + 0];
- cpy = cy + val[k + 1];
- cx += val[k + 2];
- cy += val[k + 3];
+ ctrlPointX = currentX + val[k + 2];
+ ctrlPointY = currentY + val[k + 3];
+ currentX += val[k + 4];
+ currentY += val[k + 5];
+
break;
- case 'S':
- reflectCtrl = (lastCmd == 'c' || lastCmd == 's' || lastCmd == 'C' ||
- lastCmd == 'S');
- path.curveTo(reflectCtrl ? 2 * cx - cpx : cx, reflectCtrl ? 2
- * cy - cpy : cy, val[k + 0], val[k + 1], val[k + 2],
- val[k + 3]);
- cpx = (val[k + 0]);
- cpy = (val[k + 1]);
- cx = val[k + 2];
- cy = val[k + 3];
+ case 'C': // curveto - Draws a cubic Bézier curve
+ path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
+ val[k + 4], val[k + 5]);
+ currentX = val[k + 4];
+ currentY = val[k + 5];
+ ctrlPointX = val[k + 2];
+ ctrlPointY = val[k + 3];
break;
- case 'q':
- path.quadTo(cx + val[k + 0], cy + val[k + 1], cx + val[k + 2],
- cy + val[k + 3]);
- cpx = cx + val[k + 0];
- cpy = cy + val[k + 1];
- // Note that we have to update cpx first, since cx will be updated here.
- cx += val[k + 2];
- cy += val[k + 3];
+ case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
+ reflectiveCtrlPointX = 0;
+ reflectiveCtrlPointY = 0;
+ if (previousCmd == 'c' || previousCmd == 's'
+ || previousCmd == 'C' || previousCmd == 'S') {
+ reflectiveCtrlPointX = currentX - ctrlPointX;
+ reflectiveCtrlPointY = currentY - ctrlPointY;
+ }
+ path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+ val[k + 0], val[k + 1],
+ val[k + 2], val[k + 3]);
+
+ ctrlPointX = currentX + val[k + 0];
+ ctrlPointY = currentY + val[k + 1];
+ currentX += val[k + 2];
+ currentY += val[k + 3];
break;
- case 'Q':
+ case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
+ reflectiveCtrlPointX = currentX;
+ reflectiveCtrlPointY = currentY;
+ if (previousCmd == 'c' || previousCmd == 's'
+ || previousCmd == 'C' || previousCmd == 'S') {
+ reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
+ reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
+ }
+ path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+ val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
+ ctrlPointX = val[k + 0];
+ ctrlPointY = val[k + 1];
+ currentX = val[k + 2];
+ currentY = val[k + 3];
+ break;
+ case 'q': // Draws a quadratic Bézier (relative)
+ path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
+ ctrlPointX = currentX + val[k + 0];
+ ctrlPointY = currentY + val[k + 1];
+ currentX += val[k + 2];
+ currentY += val[k + 3];
+ break;
+ case 'Q': // Draws a quadratic Bézier
path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
- cx = val[k + 2];
- cy = val[k + 3];
- cpx = val[k + 0];
- cpy = val[k + 1];
+ ctrlPointX = val[k + 0];
+ ctrlPointY = val[k + 1];
+ currentX = val[k + 2];
+ currentY = val[k + 3];
break;
- case 't':
- reflectCtrl = (lastCmd == 'q' || lastCmd == 't' || lastCmd == 'Q' ||
- lastCmd == 'T');
- tempReflectedX = reflectCtrl ? 2 * cx - cpx : cx;
- tempReflectedY = reflectCtrl ? 2 * cy - cpy : cy;
- path.quadTo(tempReflectedX, tempReflectedY, cx + val[k + 0],
- cy + val[k + 1]);
- cpx = tempReflectedX;
- cpy = tempReflectedY;
- cx += val[k + 0];
- cy += val[k + 1];
+ case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
+ reflectiveCtrlPointX = 0;
+ reflectiveCtrlPointY = 0;
+ if (previousCmd == 'q' || previousCmd == 't'
+ || previousCmd == 'Q' || previousCmd == 'T') {
+ reflectiveCtrlPointX = currentX - ctrlPointX;
+ reflectiveCtrlPointY = currentY - ctrlPointY;
+ }
+ path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+ val[k + 0], val[k + 1]);
+ ctrlPointX = currentX + reflectiveCtrlPointX;
+ ctrlPointY = currentY + reflectiveCtrlPointY;
+ currentX += val[k + 0];
+ currentY += val[k + 1];
break;
- case 'T':
- reflectCtrl = (lastCmd == 'q' || lastCmd == 't' || lastCmd == 'Q' ||
- lastCmd == 'T');
- tempReflectedX = reflectCtrl ? 2 * cx - cpx : cx;
- tempReflectedY = reflectCtrl ? 2 * cy - cpy : cy;
- path.quadTo(tempReflectedX, tempReflectedY, val[k + 0], val[k + 1]);
- cx = val[k + 0];
- cy = val[k + 1];
- cpx = tempReflectedX;
- cpy = tempReflectedY;
+ case 'T': // Draws a quadratic Bézier curve (reflective control point)
+ reflectiveCtrlPointX = currentX;
+ reflectiveCtrlPointY = currentY;
+ if (previousCmd == 'q' || previousCmd == 't'
+ || previousCmd == 'Q' || previousCmd == 'T') {
+ reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
+ reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
+ }
+ path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+ val[k + 0], val[k + 1]);
+ ctrlPointX = reflectiveCtrlPointX;
+ ctrlPointY = reflectiveCtrlPointY;
+ currentX = val[k + 0];
+ currentY = val[k + 1];
break;
- case 'a':
+ case 'a': // Draws an elliptical arc
// (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
- drawArc(path, cx, cy, val[k + 5] + cx, val[k + 6] + cy,
- val[k + 0], val[k + 1], val[k + 2], val[k + 3] != 0,
+ drawArc(path,
+ currentX,
+ currentY,
+ val[k + 5] + currentX,
+ val[k + 6] + currentY,
+ val[k + 0],
+ val[k + 1],
+ val[k + 2],
+ val[k + 3] != 0,
val[k + 4] != 0);
- cx += val[k + 5];
- cy += val[k + 6];
- cpx = cx;
- cpy = cy;
-
+ currentX += val[k + 5];
+ currentY += val[k + 6];
+ ctrlPointX = currentX;
+ ctrlPointY = currentY;
break;
- case 'A':
- drawArc(path, cx, cy, val[k + 5], val[k + 6], val[k + 0],
- val[k + 1], val[k + 2], val[k + 3] != 0,
+ case 'A': // Draws an elliptical arc
+ drawArc(path,
+ currentX,
+ currentY,
+ val[k + 5],
+ val[k + 6],
+ val[k + 0],
+ val[k + 1],
+ val[k + 2],
+ val[k + 3] != 0,
val[k + 4] != 0);
- cx = val[k + 5];
- cy = val[k + 6];
- cpx = cx;
- cpy = cy;
+ currentX = val[k + 5];
+ currentY = val[k + 6];
+ ctrlPointX = currentX;
+ ctrlPointY = currentY;
break;
-
}
- lastCmd = cmd;
+ previousCmd = cmd;
}
- current[0] = cx;
- current[1] = cy;
- current[2] = cpx;
- current[3] = cpy;
- current[4] = loopX;
- current[5] = loopY;
-
+ current[0] = currentX;
+ current[1] = currentY;
+ current[2] = ctrlPointX;
+ current[3] = ctrlPointY;
+ current[4] = currentSegmentStartX;
+ current[5] = currentSegmentStartY;
}
- private static void drawArc(@NonNull Path2D p, float x0, float y0, float x1,
+ private static void drawArc(@NonNull Path_Delegate p, float x0, float y0, float x1,
float y1, float a, float b, float theta, boolean isMoreThanHalf,
boolean isPositiveArc) {
@@ -707,7 +790,7 @@
* @param start The start angle of the arc on the ellipse
* @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
*/
- private static void arcToBezier(@NonNull Path2D p, double cx, double cy, double a,
+ private static void arcToBezier(@NonNull Path_Delegate p, double cx, double cy, double a,
double b, double e1x, double e1y, double theta, double start,
double sweep) {
// Taken from equations at:
@@ -744,8 +827,12 @@
double q2x = e2x - alpha * ep2x;
double q2y = e2y - alpha * ep2y;
- p.curveTo((float) q1x, (float) q1y, (float) q2x, (float) q2y,
- (float) e2x, (float) e2y);
+ p.cubicTo((float) q1x,
+ (float) q1y,
+ (float) q2x,
+ (float) q2y,
+ (float) e2x,
+ (float) e2y);
eta1 = eta2;
e1x = e2x;
e1y = e2y;
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index d2103c8..97195e4 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -349,7 +349,7 @@
}
@Override
- public void notifyAppStopped(IBinder token) throws RemoteException {
+ public void notifyAppStopped(IBinder token, boolean stopped) throws RemoteException {
// TODO Auto-generated method stub
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index 85e2610..4039cdf 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -484,6 +484,12 @@
}
@Override
+ public Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
+ int badgeDensity) {
+ return null;
+ }
+
+ @Override
public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
return null;
}
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 99af226..53f1912 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
@@ -60,6 +60,7 @@
import android.graphics.Bitmap;
import android.graphics.Bitmap_Delegate;
import android.graphics.Canvas;
+import android.os.Looper;
import android.preference.Preference_Delegate;
import android.view.AttachInfo_Accessor;
import android.view.BridgeInflater;
@@ -1398,6 +1399,14 @@
}
public void dispose() {
+ boolean createdLooper = false;
+ if (Looper.myLooper() == null) {
+ // Detaching the root view from the window will try to stop any running animations.
+ // The stop method checks that it can run in the looper so, if there is no current
+ // looper, we create a temporary one to complete the shutdown.
+ Bridge.prepareThread();
+ createdLooper = true;
+ }
AttachInfo_Accessor.detachFromWindow(mViewRoot);
if (mCanvas != null) {
mCanvas.release();
@@ -1412,5 +1421,9 @@
mImage = null;
mViewRoot = null;
mContentRoot = null;
+
+ if (createdLooper) {
+ Bridge.cleanupThread();
+ }
}
}
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 8a23e4b..8c3bd2f 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
@@ -269,6 +269,7 @@
"android.graphics.SweepGradient",
"android.graphics.Typeface",
"android.graphics.Xfermode",
+ "android.graphics.drawable.VectorDrawable",
"android.os.SystemClock",
"android.os.SystemProperties",
"android.text.AndroidBidi",
@@ -321,7 +322,12 @@
"org.kxml2.io.KXmlParser"
};
+ /**
+ * List of fields for which we will update the visibility to be public. This is sometimes
+ * needed when access from the delegate classes is needed.
+ */
private final static String[] PROMOTED_FIELDS = new String[] {
+ "android.graphics.drawable.VectorDrawable#mVectorState",
"android.view.Choreographer#mLastFrameTimeNanos"
};
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index ddd8f43..7dc8049 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1357,6 +1357,7 @@
append(" PROVIDER-NAME: ").append(this.providerFriendlyName).
append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN)
.append(" PRIO: ").append(this.priority)
+ .append(" HIDDEN: ").append(this.hiddenSSID)
.append('\n');
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index e2dd111..a5bfd3c 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -889,24 +889,6 @@
}
/**
- * Sets whether or not the given network is metered from a network policy
- * point of view. A network should be classified as metered when the user is
- * sensitive to heavy data usage on that connection due to monetary costs,
- * data limitations or battery/performance issues. A typical example would
- * be a wifi connection where the user was being charged for usage.
- * @param netId the integer that identifies the network configuration
- * to the supplicant.
- * @param isMetered True to mark the network as metered.
- * @return {@code true} if the operation succeeded.
- * @hide
- */
- @SystemApi
- public boolean setMetered(int netId, boolean isMetered) {
- // TODO(jjoslin): Implement
- return false;
- }
-
- /**
* Remove the specified network from the list of configured networks.
* This may result in the asynchronous delivery of state change
* events.
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 69e179d..97dd985 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -192,6 +192,11 @@
* for a given period
*/
public int stepCount;
+ /**
+ * Flag to indicate if the scan settings are targeted for PNO scan.
+ * {@hide}
+ */
+ public boolean isPnoScan;
/** Implement the Parcelable interface {@hide} */
public int describeContents() {
@@ -207,6 +212,7 @@
dest.writeInt(maxScansToCache);
dest.writeInt(maxPeriodInMs);
dest.writeInt(stepCount);
+ dest.writeInt(isPnoScan ? 1 : 0);
if (channels != null) {
dest.writeInt(channels.length);
@@ -234,6 +240,7 @@
settings.maxScansToCache = in.readInt();
settings.maxPeriodInMs = in.readInt();
settings.stepCount = in.readInt();
+ settings.isPnoScan = in.readInt() == 1;
int num_channels = in.readInt();
settings.channels = new ChannelSpec[num_channels];
for (int i = 0; i < num_channels; i++) {
@@ -436,6 +443,158 @@
};
}
+ /** {@hide} */
+ public static final String PNO_PARAMS_PNO_SETTINGS_KEY = "PnoSettings";
+ /** {@hide} */
+ public static final String PNO_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings";
+ /**
+ * PNO scan configuration parameters to be sent to {@link #startPnoScan}.
+ * Note: This structure needs to be in sync with |wifi_epno_params| struct in gscan HAL API.
+ * {@hide}
+ */
+ public static class PnoSettings implements Parcelable {
+ /**
+ * Pno network to be added to the PNO scan filtering.
+ * {@hide}
+ */
+ public static class PnoNetwork {
+ /*
+ * Pno flags bitmask to be set in {@link #PnoNetwork.flags}
+ */
+ /** Whether directed scan needs to be performed (for hidden SSIDs) */
+ public static final byte FLAG_DIRECTED_SCAN = (1 << 0);
+ /** Whether PNO event shall be triggered if the network is found on A band */
+ public static final byte FLAG_A_BAND = (1 << 1);
+ /** Whether PNO event shall be triggered if the network is found on G band */
+ public static final byte FLAG_G_BAND = (1 << 2);
+ /**
+ * Whether strict matching is required
+ * If required then the firmware must store the network's SSID and not just a hash
+ */
+ public static final byte FLAG_STRICT_MATCH = (1 << 3);
+ /**
+ * If this SSID should be considered the same network as the currently connected
+ * one for scoring.
+ */
+ public static final byte FLAG_SAME_NETWORK = (1 << 4);
+
+ /*
+ * Code for matching the beacon AUTH IE - additional codes. Bitmask to be set in
+ * {@link #PnoNetwork.authBitField}
+ */
+ /** Open Network */
+ public static final byte AUTH_CODE_OPEN = (1 << 0);
+ /** WPA_PSK or WPA2PSK */
+ public static final byte AUTH_CODE_PSK = (1 << 1);
+ /** any EAPOL */
+ public static final byte AUTH_CODE_EAPOL = (1 << 2);
+
+ /** SSID of the network */
+ public String ssid;
+ /** Network ID in wpa_supplicant */
+ public int networkId;
+ /** Assigned priority for the network */
+ public int priority;
+ /** Bitmask of the FLAG_XXX */
+ public byte flags;
+ /** Bitmask of the ATUH_XXX */
+ public byte authBitField;
+
+ /**
+ * default constructor for PnoNetwork
+ */
+ public PnoNetwork(String ssid) {
+ this.ssid = ssid;
+ flags = 0;
+ authBitField = 0;
+ }
+ }
+
+ /** Connected vs Disconnected PNO flag {@hide} */
+ public boolean isConnected;
+ /** Minimum 5GHz RSSI for a BSSID to be considered */
+ public int min5GHzRssi;
+ /** Minimum 2.4GHz RSSI for a BSSID to be considered */
+ public int min24GHzRssi;
+ /** Maximum score that a network can have before bonuses */
+ public int initialScoreMax;
+ /**
+ * Only report when there is a network's score this much higher
+ * than the current connection.
+ */
+ public int currentConnectionBonus;
+ /** score bonus for all networks with the same network flag */
+ public int sameNetworkBonus;
+ /** score bonus for networks that are not open */
+ public int secureBonus;
+ /** 5GHz RSSI score bonus (applied to all 5GHz networks) */
+ public int band5GHzBonus;
+ /** Pno Network filter list */
+ public PnoNetwork[] networkList;
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(isConnected ? 1 : 0);
+ dest.writeInt(min5GHzRssi);
+ dest.writeInt(min24GHzRssi);
+ dest.writeInt(initialScoreMax);
+ dest.writeInt(currentConnectionBonus);
+ dest.writeInt(sameNetworkBonus);
+ dest.writeInt(secureBonus);
+ dest.writeInt(band5GHzBonus);
+ if (networkList != null) {
+ dest.writeInt(networkList.length);
+ for (int i = 0; i < networkList.length; i++) {
+ dest.writeString(networkList[i].ssid);
+ dest.writeInt(networkList[i].networkId);
+ dest.writeInt(networkList[i].priority);
+ dest.writeByte(networkList[i].flags);
+ dest.writeByte(networkList[i].authBitField);
+ }
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<PnoSettings> CREATOR =
+ new Creator<PnoSettings>() {
+ public PnoSettings createFromParcel(Parcel in) {
+ PnoSettings settings = new PnoSettings();
+ settings.isConnected = in.readInt() == 1;
+ settings.min5GHzRssi = in.readInt();
+ settings.min24GHzRssi = in.readInt();
+ settings.initialScoreMax = in.readInt();
+ settings.currentConnectionBonus = in.readInt();
+ settings.sameNetworkBonus = in.readInt();
+ settings.secureBonus = in.readInt();
+ settings.band5GHzBonus = in.readInt();
+ int numNetworks = in.readInt();
+ settings.networkList = new PnoNetwork[numNetworks];
+ for (int i = 0; i < numNetworks; i++) {
+ String ssid = in.readString();
+ PnoNetwork network = new PnoNetwork(ssid);
+ network.networkId = in.readInt();
+ network.priority = in.readInt();
+ network.flags = in.readByte();
+ network.authBitField = in.readByte();
+ settings.networkList[i] = network;
+ }
+ return settings;
+ }
+
+ public PnoSettings[] newArray(int size) {
+ return new PnoSettings[size];
+ }
+ };
+
+ }
+
/**
* interface to get scan events on; specify this on {@link #startBackgroundScan} or
* {@link #startScan}
@@ -456,6 +615,18 @@
public void onFullResult(ScanResult fullScanResult);
}
+ /**
+ * interface to get PNO scan events on; specify this on {@link #startDisconnectedPnoScan} and
+ * {@link #startConnectedPnoScan}.
+ * {@hide}
+ */
+ public interface PnoScanListener extends ScanListener {
+ /**
+ * Invoked when one of the PNO networks are found in scan results.
+ */
+ void onPnoNetworkFound(ScanResult[] results);
+ }
+
/** start wifi scan in background
* @param settings specifies various parameters for the scan; for more information look at
* {@link ScanSettings}
@@ -521,6 +692,75 @@
sAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key);
}
+ private void startPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, int key) {
+ // Bundle up both the settings and send it across.
+ Bundle pnoParams = new Bundle();
+ if (pnoParams == null) return;
+ // Set the PNO scan flag.
+ scanSettings.isPnoScan = true;
+ pnoParams.putParcelable(PNO_PARAMS_SCAN_SETTINGS_KEY, scanSettings);
+ pnoParams.putParcelable(PNO_PARAMS_PNO_SETTINGS_KEY, pnoSettings);
+ sAsyncChannel.sendMessage(CMD_START_PNO_SCAN, 0, key, pnoParams);
+ }
+ /**
+ * Start wifi connected PNO scan
+ * @param scanSettings specifies various parameters for the scan; for more information look at
+ * {@link ScanSettings}
+ * @param pnoSettings specifies various parameters for PNO; for more information look at
+ * {@link PnoSettings}
+ * @param listener specifies the object to report events to. This object is also treated as a
+ * key for this scan, and must also be specified to cancel the scan. Multiple
+ * scans should also not share this object.
+ * {@hide}
+ */
+ public void startConnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,
+ PnoScanListener listener) {
+ Preconditions.checkNotNull(listener, "listener cannot be null");
+ Preconditions.checkNotNull(pnoSettings, "pnoSettings cannot be null");
+ int key = addListener(listener);
+ if (key == INVALID_KEY) return;
+ validateChannel();
+ pnoSettings.isConnected = true;
+ startPnoScan(scanSettings, pnoSettings, key);
+ }
+ /**
+ * Start wifi disconnected PNO scan
+ * @param scanSettings specifies various parameters for the scan; for more information look at
+ * {@link ScanSettings}
+ * @param pnoSettings specifies various parameters for PNO; for more information look at
+ * {@link PnoSettings}
+ * @param listener specifies the object to report events to. This object is also treated as a
+ * key for this scan, and must also be specified to cancel the scan. Multiple
+ * scans should also not share this object.
+ * {@hide}
+ */
+ public void startDisconnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,
+ PnoScanListener listener) {
+ Preconditions.checkNotNull(listener, "listener cannot be null");
+ Preconditions.checkNotNull(pnoSettings, "pnoSettings cannot be null");
+ int key = addListener(listener);
+ if (key == INVALID_KEY) return;
+ validateChannel();
+ pnoSettings.isConnected = false;
+ startPnoScan(scanSettings, pnoSettings, key);
+ }
+ /**
+ * Stop an ongoing wifi PNO scan
+ * @param pnoSettings specifies various parameters for PNO; for more information look at
+ * {@link PnoSettings}
+ * @param listener specifies which scan to cancel; must be same object as passed in {@link
+ * #startPnoScan}
+ * TODO(rpius): Check if we can remove pnoSettings param in stop.
+ * {@hide}
+ */
+ public void stopPnoScan(PnoSettings pnoSettings, ScanListener listener) {
+ Preconditions.checkNotNull(listener, "listener cannot be null");
+ int key = removeListener(listener);
+ if (key == INVALID_KEY) return;
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_STOP_PNO_SCAN, 0, key, pnoSettings);
+ }
+
/** specifies information about an access point of interest */
public static class BssidInfo {
/** bssid of the access point; in XX:XX:XX:XX:XX:XX format */
@@ -824,6 +1064,12 @@
public static final int CMD_STOP_SINGLE_SCAN = BASE + 22;
/** @hide */
public static final int CMD_SINGLE_SCAN_COMPLETED = BASE + 23;
+ /** @hide */
+ public static final int CMD_START_PNO_SCAN = BASE + 24;
+ /** @hide */
+ public static final int CMD_STOP_PNO_SCAN = BASE + 25;
+ /** @hide */
+ public static final int CMD_PNO_NETWORK_FOUND = BASE + 26;
private Context mContext;
private IWifiScanner mService;
@@ -1110,6 +1356,10 @@
if (DBG) Log.d(TAG, "removing listener for single scan");
removeListener(msg.arg2);
break;
+ case CMD_PNO_NETWORK_FOUND:
+ ((PnoScanListener) listener).onPnoNetworkFound(
+ ((ParcelableScanResults) msg.obj).getResults());
+ return;
default:
if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
return;