Merge "Add tileMode support into GradientColor" into nyc-dev
diff --git a/Android.mk b/Android.mk
index 2ee7600..ffc0421 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 \
@@ -241,11 +241,13 @@
core/java/android/service/notification/IStatusBarNotificationHolder.aidl \
core/java/android/service/notification/IConditionListener.aidl \
core/java/android/service/notification/IConditionProvider.aidl \
+ core/java/android/service/vr/IVrListener.aidl \
core/java/android/print/ILayoutResultCallback.aidl \
core/java/android/print/IPrinterDiscoveryObserver.aidl \
core/java/android/print/IPrintDocumentAdapter.aidl \
core/java/android/print/IPrintDocumentAdapterObserver.aidl \
core/java/android/print/IPrintJobStateChangeListener.aidl \
+ core/java/android/print/IPrintServicesChangeListener.aidl \
core/java/android/print/IPrintManager.aidl \
core/java/android/print/IPrintSpooler.aidl \
core/java/android/print/IPrintSpoolerCallbacks.aidl \
@@ -455,6 +457,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 +583,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 014ae35..5ec93cb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -38,6 +38,7 @@
field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
+ field public static final java.lang.String BIND_VR_LISTENER_SERVICE = "android.permission.BIND_VR_LISTENER_SERVICE";
field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
@@ -114,6 +115,7 @@
field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
+ field public static final java.lang.String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
field public static final java.lang.String SET_ALWAYS_FINISH = "android.permission.SET_ALWAYS_FINISH";
field public static final java.lang.String SET_ANIMATION_SCALE = "android.permission.SET_ANIMATION_SCALE";
@@ -3604,7 +3606,7 @@
method public deprecated void setTitleColor(int);
method public void setVisible(boolean);
method public final void setVolumeControlStream(int);
- method public void setVrMode(boolean);
+ method public void setVrModeEnabled(boolean, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
method public boolean shouldShowRequestPermissionRationale(java.lang.String);
method public boolean shouldUpRecreateTask(android.content.Intent);
method public boolean showAssist(android.os.Bundle);
@@ -5258,7 +5260,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);
@@ -5610,8 +5612,6 @@
method public void enableCarMode(int);
method public int getCurrentModeType();
method public int getNightMode();
- method public boolean isNightModeLocked();
- method public boolean isUiModeLocked();
method public void setNightMode(int);
field public static java.lang.String ACTION_ENTER_CAR_MODE;
field public static java.lang.String ACTION_ENTER_DESK_MODE;
@@ -5713,6 +5713,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();
@@ -10467,7 +10468,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 {
@@ -19157,168 +19157,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 {
@@ -19331,7 +19273,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
}
@@ -19348,34 +19290,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 {
@@ -19387,7 +19329,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
}
@@ -19406,22 +19348,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 {
@@ -19536,8 +19478,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);
@@ -19562,7 +19504,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";
@@ -19780,7 +19722,7 @@
method public void adjustVolume(int, int);
method public void dispatchMediaKeyEvent(android.view.KeyEvent);
method public int generateAudioSessionId();
- method public android.media.AudioRecordConfiguration[] getActiveRecordConfigurations();
+ method public android.media.AudioRecordingConfiguration[] getActiveRecordingConfigurations();
method public android.media.AudioDeviceInfo[] getDevices(int);
method public int getMode();
method public java.lang.String getParameters(java.lang.String);
@@ -19926,7 +19868,7 @@
public static abstract class AudioManager.AudioRecordingCallback {
ctor public AudioManager.AudioRecordingCallback();
- method public void onRecordConfigChanged();
+ method public void onRecordConfigChanged(android.media.AudioRecordingConfiguration[]);
}
public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -20000,7 +19942,7 @@
method public abstract void onRoutingChanged(android.media.AudioRecord);
}
- public final class AudioRecordConfiguration implements android.os.Parcelable {
+ public final class AudioRecordingConfiguration implements android.os.Parcelable {
method public int describeContents();
method public android.media.AudioDeviceInfo getAudioDevice();
method public int getClientAudioSessionId();
@@ -20008,7 +19950,7 @@
method public android.media.AudioFormat getClientFormat();
method public android.media.AudioFormat getFormat();
method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.media.AudioRecordConfiguration> CREATOR;
+ field public static final android.os.Parcelable.Creator<android.media.AudioRecordingConfiguration> CREATOR;
}
public abstract interface AudioRouting {
@@ -20444,6 +20386,7 @@
field public static final int ERROR_NO_KEY = 1; // 0x1
field public static final int ERROR_RESOURCE_BUSY = 3; // 0x3
field public static final int ERROR_SESSION_NOT_OPENED = 5; // 0x5
+ field public static final int ERROR_UNSUPPORTED_OPERATION = 6; // 0x6
}
public static final class MediaCodec.CryptoInfo {
@@ -20910,6 +20853,7 @@
method public final void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
method public final void setDataSource(java.lang.String) throws java.io.IOException;
+ method public final void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public final void setDataSource(java.io.FileDescriptor) throws java.io.IOException;
method public final void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException;
method public void unselectTrack(int);
@@ -20994,6 +20938,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";
@@ -29106,6 +29051,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();
@@ -31771,6 +31718,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";
@@ -32225,6 +32173,7 @@
field public static final java.lang.String ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE = "android.settings.VOICE_CONTROL_BATTERY_SAVER_MODE";
field public static final java.lang.String ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE = "android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE";
field public static final java.lang.String ACTION_VOICE_INPUT_SETTINGS = "android.settings.VOICE_INPUT_SETTINGS";
+ field public static final java.lang.String ACTION_VR_LISTENER_SETTINGS = "android.settings.VR_LISTENER_SETTINGS";
field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
field public static final java.lang.String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS";
@@ -32262,6 +32211,7 @@
field public static final java.lang.String AUTO_TIME = "auto_time";
field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
field public static final java.lang.String BLUETOOTH_ON = "bluetooth_on";
+ field public static final java.lang.String BOOT_COUNT = "boot_count";
field public static final java.lang.String CONTACT_METADATA_SYNC = "contact_metadata_sync";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String DATA_ROAMING = "data_roaming";
@@ -34293,7 +34243,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>);
@@ -34304,6 +34255,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
@@ -34538,7 +34492,6 @@
method public static void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
method public final void requestUnbind() throws android.os.RemoteException;
method public final void setNotificationsShown(java.lang.String[]);
- field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications";
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
@@ -34833,6 +34786,17 @@
}
+package android.service.vr {
+
+ public abstract class VrListenerService extends android.app.Service {
+ ctor public VrListenerService();
+ method public static final boolean isVrModePackageEnabled(android.content.Context, android.content.ComponentName);
+ method public android.os.IBinder onBind(android.content.Intent);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.vr.VrListenerService";
+ }
+
+}
+
package android.service.wallpaper {
public abstract class WallpaperService extends android.app.Service {
@@ -38530,7 +38494,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);
}
@@ -40142,6 +40105,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[]);
@@ -50453,6 +50417,7 @@
method public static long doubleToRawLongBits(double);
method public double doubleValue();
method public float floatValue();
+ method public static int hashCode(double);
method public int intValue();
method public static boolean isInfinite(double);
method public boolean isInfinite();
@@ -50460,11 +50425,15 @@
method public boolean isNaN();
method public static double longBitsToDouble(long);
method public long longValue();
+ method public static double max(double, double);
+ method public static double min(double, double);
method public static double parseDouble(java.lang.String) throws java.lang.NumberFormatException;
+ method public static double sum(double, double);
method public static java.lang.String toHexString(double);
method public static java.lang.String toString(double);
method public static java.lang.Double valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Double valueOf(double);
+ field public static final int BYTES = 8; // 0x8
field public static final int MAX_EXPONENT = 1023; // 0x3ff
field public static final double MAX_VALUE = 1.7976931348623157E308;
field public static final int MIN_EXPONENT = -1022; // 0xfffffc02
@@ -50627,10 +50596,13 @@
method public static java.lang.Integer getInteger(java.lang.String);
method public static java.lang.Integer getInteger(java.lang.String, int);
method public static java.lang.Integer getInteger(java.lang.String, java.lang.Integer);
+ method public static int hashCode(int);
method public static int highestOneBit(int);
method public int intValue();
method public long longValue();
method public static int lowestOneBit(int);
+ method public static int max(int, int);
+ method public static int min(int, int);
method public static int numberOfLeadingZeros(int);
method public static int numberOfTrailingZeros(int);
method public static int parseInt(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50640,6 +50612,7 @@
method public static int rotateLeft(int, int);
method public static int rotateRight(int, int);
method public static int signum(int);
+ method public static int sum(int, int);
method public static java.lang.String toBinaryString(int);
method public static java.lang.String toHexString(int);
method public static java.lang.String toOctalString(int);
@@ -50648,6 +50621,7 @@
method public static java.lang.Integer valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Integer valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Integer valueOf(int);
+ field public static final int BYTES = 4; // 0x4
field public static final int MAX_VALUE = 2147483647; // 0x7fffffff
field public static final int MIN_VALUE = -2147483648; // 0x80000000
field public static final int SIZE = 32; // 0x20
@@ -50689,10 +50663,13 @@
method public static java.lang.Long getLong(java.lang.String);
method public static java.lang.Long getLong(java.lang.String, long);
method public static java.lang.Long getLong(java.lang.String, java.lang.Long);
+ method public static int hashCode(long);
method public static long highestOneBit(long);
method public int intValue();
method public long longValue();
method public static long lowestOneBit(long);
+ method public static long max(long, long);
+ method public static long min(long, long);
method public static int numberOfLeadingZeros(long);
method public static int numberOfTrailingZeros(long);
method public static long parseLong(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50702,6 +50679,7 @@
method public static long rotateLeft(long, int);
method public static long rotateRight(long, int);
method public static int signum(long);
+ method public static long sum(long, long);
method public static java.lang.String toBinaryString(long);
method public static java.lang.String toHexString(long);
method public static java.lang.String toOctalString(long);
@@ -57751,9 +57729,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 {
@@ -58056,6 +58035,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);
@@ -58227,7 +58279,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 3b1f3f8..4224792 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -52,6 +52,7 @@
field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
+ field public static final java.lang.String BIND_VR_LISTENER_SERVICE = "android.permission.BIND_VR_LISTENER_SERVICE";
field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
@@ -193,6 +194,7 @@
field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
+ field public static final java.lang.String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
field public static final java.lang.String SERIAL_PORT = "android.permission.SERIAL_PORT";
field public static final java.lang.String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER";
field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
@@ -3721,7 +3723,7 @@
method public deprecated void setTitleColor(int);
method public void setVisible(boolean);
method public final void setVolumeControlStream(int);
- method public void setVrMode(boolean);
+ method public void setVrModeEnabled(boolean, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
method public boolean shouldShowRequestPermissionRationale(java.lang.String);
method public boolean shouldUpRecreateTask(android.content.Intent);
method public boolean showAssist(android.os.Bundle);
@@ -5390,7 +5392,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);
@@ -5742,8 +5744,6 @@
method public void enableCarMode(int);
method public int getCurrentModeType();
method public int getNightMode();
- method public boolean isNightModeLocked();
- method public boolean isUiModeLocked();
method public void setNightMode(int);
field public static java.lang.String ACTION_ENTER_CAR_MODE;
field public static java.lang.String ACTION_ENTER_DESK_MODE;
@@ -5845,6 +5845,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);
@@ -9928,6 +9929,7 @@
method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
method public android.graphics.drawable.Drawable loadLogo(android.content.pm.PackageManager);
+ method public java.lang.CharSequence loadSafeLabel(android.content.pm.PackageManager);
method public android.graphics.drawable.Drawable loadUnbadgedIcon(android.content.pm.PackageManager);
method public android.content.res.XmlResourceParser loadXmlMetaData(android.content.pm.PackageManager, java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
@@ -10186,6 +10188,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
@@ -10858,7 +10862,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 {
@@ -20327,168 +20330,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 {
@@ -20501,7 +20446,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
}
@@ -20518,34 +20463,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 {
@@ -20557,7 +20502,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
}
@@ -20576,22 +20521,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 {
@@ -20953,8 +20898,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);
@@ -20983,7 +20928,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";
@@ -21258,7 +21203,7 @@
method public void adjustVolume(int, int);
method public void dispatchMediaKeyEvent(android.view.KeyEvent);
method public int generateAudioSessionId();
- method public android.media.AudioRecordConfiguration[] getActiveRecordConfigurations();
+ method public android.media.AudioRecordingConfiguration[] getActiveRecordingConfigurations();
method public android.media.AudioDeviceInfo[] getDevices(int);
method public int getMode();
method public java.lang.String getParameters(java.lang.String);
@@ -21412,7 +21357,7 @@
public static abstract class AudioManager.AudioRecordingCallback {
ctor public AudioManager.AudioRecordingCallback();
- method public void onRecordConfigChanged();
+ method public void onRecordConfigChanged(android.media.AudioRecordingConfiguration[]);
}
public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -21489,7 +21434,7 @@
method public abstract void onRoutingChanged(android.media.AudioRecord);
}
- public final class AudioRecordConfiguration implements android.os.Parcelable {
+ public final class AudioRecordingConfiguration implements android.os.Parcelable {
method public int describeContents();
method public android.media.AudioDeviceInfo getAudioDevice();
method public int getClientAudioSessionId();
@@ -21497,7 +21442,7 @@
method public android.media.AudioFormat getClientFormat();
method public android.media.AudioFormat getFormat();
method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.media.AudioRecordConfiguration> CREATOR;
+ field public static final android.os.Parcelable.Creator<android.media.AudioRecordingConfiguration> CREATOR;
}
public abstract interface AudioRouting {
@@ -21933,6 +21878,7 @@
field public static final int ERROR_NO_KEY = 1; // 0x1
field public static final int ERROR_RESOURCE_BUSY = 3; // 0x3
field public static final int ERROR_SESSION_NOT_OPENED = 5; // 0x5
+ field public static final int ERROR_UNSUPPORTED_OPERATION = 6; // 0x6
}
public static final class MediaCodec.CryptoInfo {
@@ -22399,6 +22345,7 @@
method public final void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
method public final void setDataSource(java.lang.String) throws java.io.IOException;
+ method public final void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public final void setDataSource(java.io.FileDescriptor) throws java.io.IOException;
method public final void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException;
method public void unselectTrack(int);
@@ -22483,6 +22430,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";
@@ -26720,7 +26668,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);
@@ -31397,6 +31344,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();
@@ -34154,6 +34103,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";
@@ -34710,6 +34660,7 @@
field public static final java.lang.String ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE = "android.settings.VOICE_CONTROL_BATTERY_SAVER_MODE";
field public static final java.lang.String ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE = "android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE";
field public static final java.lang.String ACTION_VOICE_INPUT_SETTINGS = "android.settings.VOICE_INPUT_SETTINGS";
+ field public static final java.lang.String ACTION_VR_LISTENER_SETTINGS = "android.settings.VR_LISTENER_SETTINGS";
field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
field public static final java.lang.String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS";
@@ -34747,6 +34698,7 @@
field public static final java.lang.String AUTO_TIME = "auto_time";
field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
field public static final java.lang.String BLUETOOTH_ON = "bluetooth_on";
+ field public static final java.lang.String BOOT_COUNT = "boot_count";
field public static final java.lang.String CONTACT_METADATA_SYNC = "contact_metadata_sync";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String DATA_ROAMING = "data_roaming";
@@ -36781,7 +36733,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>);
@@ -36792,6 +36745,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
@@ -37002,37 +36958,6 @@
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
}
- public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
- ctor public NotificationAssistantService();
- method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
- method public final android.os.IBinder onBind(android.content.Intent);
- method public void onNotificationActionClick(java.lang.String, long, int);
- method public void onNotificationClick(java.lang.String, long);
- method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
- method public void onNotificationRemoved(java.lang.String, long, int);
- method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
- field public static final int REASON_APP_CANCEL = 8; // 0x8
- field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
- field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
- field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
- field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
- field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
- field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
- field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
- field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
- field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
- field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
- field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
- field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
- field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
- field public static final int REASON_USER_STOPPED = 6; // 0x6
- field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
- }
-
- public class NotificationAssistantService.Adjustment {
- ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
- }
-
public abstract class NotificationListenerService extends android.app.Service {
ctor public NotificationListenerService();
method public final void cancelAllNotifications();
@@ -37063,7 +36988,6 @@
method public final void setNotificationsShown(java.lang.String[]);
method public final void setOnNotificationPostedTrim(int);
method public void unregisterAsSystemService() throws android.os.RemoteException;
- field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications";
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
@@ -37103,6 +37027,37 @@
field public static final android.os.Parcelable.Creator<android.service.notification.NotificationListenerService.RankingMap> CREATOR;
}
+ public abstract class NotificationRankerService extends android.service.notification.NotificationListenerService {
+ ctor public NotificationRankerService();
+ method public final void adjustImportance(java.lang.String, android.service.notification.NotificationRankerService.Adjustment);
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public void onNotificationActionClick(java.lang.String, long, int);
+ method public void onNotificationClick(java.lang.String, long);
+ method public abstract android.service.notification.NotificationRankerService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+ method public void onNotificationRemoved(java.lang.String, long, int);
+ method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
+ field public static final int REASON_APP_CANCEL = 8; // 0x8
+ field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+ field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
+ field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
+ field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
+ field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
+ field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
+ field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
+ field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
+ field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
+ field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
+ field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
+ field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
+ field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
+ field public static final int REASON_USER_STOPPED = 6; // 0x6
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationRankerService";
+ }
+
+ public class NotificationRankerService.Adjustment {
+ ctor public NotificationRankerService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
+ }
+
public class StatusBarNotification implements android.os.Parcelable {
ctor public StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
ctor public StatusBarNotification(android.os.Parcel);
@@ -37416,6 +37371,17 @@
}
+package android.service.vr {
+
+ public abstract class VrListenerService extends android.app.Service {
+ ctor public VrListenerService();
+ method public static final boolean isVrModePackageEnabled(android.content.Context, android.content.ComponentName);
+ method public android.os.IBinder onBind(android.content.Intent);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.vr.VrListenerService";
+ }
+
+}
+
package android.service.wallpaper {
public abstract class WallpaperService extends android.app.Service {
@@ -41295,7 +41261,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);
}
@@ -42907,6 +42872,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[]);
@@ -53555,6 +53521,7 @@
method public static long doubleToRawLongBits(double);
method public double doubleValue();
method public float floatValue();
+ method public static int hashCode(double);
method public int intValue();
method public static boolean isInfinite(double);
method public boolean isInfinite();
@@ -53562,11 +53529,15 @@
method public boolean isNaN();
method public static double longBitsToDouble(long);
method public long longValue();
+ method public static double max(double, double);
+ method public static double min(double, double);
method public static double parseDouble(java.lang.String) throws java.lang.NumberFormatException;
+ method public static double sum(double, double);
method public static java.lang.String toHexString(double);
method public static java.lang.String toString(double);
method public static java.lang.Double valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Double valueOf(double);
+ field public static final int BYTES = 8; // 0x8
field public static final int MAX_EXPONENT = 1023; // 0x3ff
field public static final double MAX_VALUE = 1.7976931348623157E308;
field public static final int MIN_EXPONENT = -1022; // 0xfffffc02
@@ -53729,10 +53700,13 @@
method public static java.lang.Integer getInteger(java.lang.String);
method public static java.lang.Integer getInteger(java.lang.String, int);
method public static java.lang.Integer getInteger(java.lang.String, java.lang.Integer);
+ method public static int hashCode(int);
method public static int highestOneBit(int);
method public int intValue();
method public long longValue();
method public static int lowestOneBit(int);
+ method public static int max(int, int);
+ method public static int min(int, int);
method public static int numberOfLeadingZeros(int);
method public static int numberOfTrailingZeros(int);
method public static int parseInt(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -53742,6 +53716,7 @@
method public static int rotateLeft(int, int);
method public static int rotateRight(int, int);
method public static int signum(int);
+ method public static int sum(int, int);
method public static java.lang.String toBinaryString(int);
method public static java.lang.String toHexString(int);
method public static java.lang.String toOctalString(int);
@@ -53750,6 +53725,7 @@
method public static java.lang.Integer valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Integer valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Integer valueOf(int);
+ field public static final int BYTES = 4; // 0x4
field public static final int MAX_VALUE = 2147483647; // 0x7fffffff
field public static final int MIN_VALUE = -2147483648; // 0x80000000
field public static final int SIZE = 32; // 0x20
@@ -53791,10 +53767,13 @@
method public static java.lang.Long getLong(java.lang.String);
method public static java.lang.Long getLong(java.lang.String, long);
method public static java.lang.Long getLong(java.lang.String, java.lang.Long);
+ method public static int hashCode(long);
method public static long highestOneBit(long);
method public int intValue();
method public long longValue();
method public static long lowestOneBit(long);
+ method public static long max(long, long);
+ method public static long min(long, long);
method public static int numberOfLeadingZeros(long);
method public static int numberOfTrailingZeros(long);
method public static long parseLong(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -53804,6 +53783,7 @@
method public static long rotateLeft(long, int);
method public static long rotateRight(long, int);
method public static int signum(long);
+ method public static long sum(long, long);
method public static java.lang.String toBinaryString(long);
method public static java.lang.String toHexString(long);
method public static java.lang.String toOctalString(long);
@@ -60853,9 +60833,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 {
@@ -61158,6 +61139,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);
@@ -61329,7 +61383,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 580af72..894971b 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -38,6 +38,7 @@
field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
+ field public static final java.lang.String BIND_VR_LISTENER_SERVICE = "android.permission.BIND_VR_LISTENER_SERVICE";
field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
@@ -114,6 +115,7 @@
field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
+ field public static final java.lang.String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
field public static final java.lang.String SET_ALWAYS_FINISH = "android.permission.SET_ALWAYS_FINISH";
field public static final java.lang.String SET_ANIMATION_SCALE = "android.permission.SET_ANIMATION_SCALE";
@@ -3604,7 +3606,7 @@
method public deprecated void setTitleColor(int);
method public void setVisible(boolean);
method public final void setVolumeControlStream(int);
- method public void setVrMode(boolean);
+ method public void setVrModeEnabled(boolean, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
method public boolean shouldShowRequestPermissionRationale(java.lang.String);
method public boolean shouldUpRecreateTask(android.content.Intent);
method public boolean showAssist(android.os.Bundle);
@@ -5258,7 +5260,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 +5717,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 +10478,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 +19167,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 +19283,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 +19300,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 +19339,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 +19358,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 +19489,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 +19515,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";
@@ -19789,7 +19733,7 @@
method public void adjustVolume(int, int);
method public void dispatchMediaKeyEvent(android.view.KeyEvent);
method public int generateAudioSessionId();
- method public android.media.AudioRecordConfiguration[] getActiveRecordConfigurations();
+ method public android.media.AudioRecordingConfiguration[] getActiveRecordingConfigurations();
method public android.media.AudioDeviceInfo[] getDevices(int);
method public int getMode();
method public java.lang.String getParameters(java.lang.String);
@@ -19935,7 +19879,7 @@
public static abstract class AudioManager.AudioRecordingCallback {
ctor public AudioManager.AudioRecordingCallback();
- method public void onRecordConfigChanged();
+ method public void onRecordConfigChanged(android.media.AudioRecordingConfiguration[]);
}
public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -20009,7 +19953,7 @@
method public abstract void onRoutingChanged(android.media.AudioRecord);
}
- public final class AudioRecordConfiguration implements android.os.Parcelable {
+ public final class AudioRecordingConfiguration implements android.os.Parcelable {
method public int describeContents();
method public android.media.AudioDeviceInfo getAudioDevice();
method public int getClientAudioSessionId();
@@ -20017,7 +19961,7 @@
method public android.media.AudioFormat getClientFormat();
method public android.media.AudioFormat getFormat();
method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.media.AudioRecordConfiguration> CREATOR;
+ field public static final android.os.Parcelable.Creator<android.media.AudioRecordingConfiguration> CREATOR;
}
public abstract interface AudioRouting {
@@ -20453,6 +20397,7 @@
field public static final int ERROR_NO_KEY = 1; // 0x1
field public static final int ERROR_RESOURCE_BUSY = 3; // 0x3
field public static final int ERROR_SESSION_NOT_OPENED = 5; // 0x5
+ field public static final int ERROR_UNSUPPORTED_OPERATION = 6; // 0x6
}
public static final class MediaCodec.CryptoInfo {
@@ -20919,6 +20864,7 @@
method public final void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
method public final void setDataSource(java.lang.String) throws java.io.IOException;
+ method public final void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public final void setDataSource(java.io.FileDescriptor) throws java.io.IOException;
method public final void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException;
method public void unselectTrack(int);
@@ -21003,6 +20949,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 +29062,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 +31733,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";
@@ -32238,6 +32188,7 @@
field public static final java.lang.String ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE = "android.settings.VOICE_CONTROL_BATTERY_SAVER_MODE";
field public static final java.lang.String ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE = "android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE";
field public static final java.lang.String ACTION_VOICE_INPUT_SETTINGS = "android.settings.VOICE_INPUT_SETTINGS";
+ field public static final java.lang.String ACTION_VR_LISTENER_SETTINGS = "android.settings.VR_LISTENER_SETTINGS";
field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
field public static final java.lang.String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS";
@@ -32275,6 +32226,7 @@
field public static final java.lang.String AUTO_TIME = "auto_time";
field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
field public static final java.lang.String BLUETOOTH_ON = "bluetooth_on";
+ field public static final java.lang.String BOOT_COUNT = "boot_count";
field public static final java.lang.String CONTACT_METADATA_SYNC = "contact_metadata_sync";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String DATA_ROAMING = "data_roaming";
@@ -34308,7 +34260,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 +34272,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
@@ -34553,7 +34509,6 @@
method public static void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
method public final void requestUnbind() throws android.os.RemoteException;
method public final void setNotificationsShown(java.lang.String[]);
- field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications";
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
@@ -34848,6 +34803,17 @@
}
+package android.service.vr {
+
+ public abstract class VrListenerService extends android.app.Service {
+ ctor public VrListenerService();
+ method public static final boolean isVrModePackageEnabled(android.content.Context, android.content.ComponentName);
+ method public android.os.IBinder onBind(android.content.Intent);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.vr.VrListenerService";
+ }
+
+}
+
package android.service.wallpaper {
public abstract class WallpaperService extends android.app.Service {
@@ -38547,7 +38513,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 +40124,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[]);
@@ -50470,6 +50436,7 @@
method public static long doubleToRawLongBits(double);
method public double doubleValue();
method public float floatValue();
+ method public static int hashCode(double);
method public int intValue();
method public static boolean isInfinite(double);
method public boolean isInfinite();
@@ -50477,11 +50444,15 @@
method public boolean isNaN();
method public static double longBitsToDouble(long);
method public long longValue();
+ method public static double max(double, double);
+ method public static double min(double, double);
method public static double parseDouble(java.lang.String) throws java.lang.NumberFormatException;
+ method public static double sum(double, double);
method public static java.lang.String toHexString(double);
method public static java.lang.String toString(double);
method public static java.lang.Double valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Double valueOf(double);
+ field public static final int BYTES = 8; // 0x8
field public static final int MAX_EXPONENT = 1023; // 0x3ff
field public static final double MAX_VALUE = 1.7976931348623157E308;
field public static final int MIN_EXPONENT = -1022; // 0xfffffc02
@@ -50644,10 +50615,13 @@
method public static java.lang.Integer getInteger(java.lang.String);
method public static java.lang.Integer getInteger(java.lang.String, int);
method public static java.lang.Integer getInteger(java.lang.String, java.lang.Integer);
+ method public static int hashCode(int);
method public static int highestOneBit(int);
method public int intValue();
method public long longValue();
method public static int lowestOneBit(int);
+ method public static int max(int, int);
+ method public static int min(int, int);
method public static int numberOfLeadingZeros(int);
method public static int numberOfTrailingZeros(int);
method public static int parseInt(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50657,6 +50631,7 @@
method public static int rotateLeft(int, int);
method public static int rotateRight(int, int);
method public static int signum(int);
+ method public static int sum(int, int);
method public static java.lang.String toBinaryString(int);
method public static java.lang.String toHexString(int);
method public static java.lang.String toOctalString(int);
@@ -50665,6 +50640,7 @@
method public static java.lang.Integer valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Integer valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Integer valueOf(int);
+ field public static final int BYTES = 4; // 0x4
field public static final int MAX_VALUE = 2147483647; // 0x7fffffff
field public static final int MIN_VALUE = -2147483648; // 0x80000000
field public static final int SIZE = 32; // 0x20
@@ -50706,10 +50682,13 @@
method public static java.lang.Long getLong(java.lang.String);
method public static java.lang.Long getLong(java.lang.String, long);
method public static java.lang.Long getLong(java.lang.String, java.lang.Long);
+ method public static int hashCode(long);
method public static long highestOneBit(long);
method public int intValue();
method public long longValue();
method public static long lowestOneBit(long);
+ method public static long max(long, long);
+ method public static long min(long, long);
method public static int numberOfLeadingZeros(long);
method public static int numberOfTrailingZeros(long);
method public static long parseLong(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50719,6 +50698,7 @@
method public static long rotateLeft(long, int);
method public static long rotateRight(long, int);
method public static int signum(long);
+ method public static long sum(long, long);
method public static java.lang.String toBinaryString(long);
method public static java.lang.String toHexString(long);
method public static java.lang.String toOctalString(long);
@@ -57768,9 +57748,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 {
@@ -58073,6 +58054,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);
@@ -58244,7 +58298,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..e6c5768 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -577,7 +577,7 @@
return;
}
List<ResolveInfo> activities = pm.queryIntentActivities(intent, mimeType, 0,
- mUserId);
+ mUserId).getList();
if (activities == null || activities.size() <= 0) {
System.err.println("Error: Intent does not match any activities: "
+ intent);
@@ -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/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 8f361ce..ea53e59 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -68,8 +68,7 @@
// ---------------------------------------------------------------------------
-BootAnimation::BootAnimation() : Thread(false), mZip(NULL)
-{
+BootAnimation::BootAnimation() : Thread(false), mZip(NULL), mClockEnabled(true) {
mSession = new SurfaceComposerClient();
}
@@ -450,6 +449,69 @@
return true;
}
+// The time glyphs are stored in a single image of height 64 pixels. Each digit is 40 pixels wide,
+// and the colon character is half that at 20 pixels. The glyph order is '0123456789:'.
+// We render 24 hour time.
+void BootAnimation::drawTime(const Texture& clockTex, const int yPos) {
+ static constexpr char TIME_FORMAT[] = "%H:%M";
+ static constexpr int TIME_LENGTH = sizeof(TIME_FORMAT);
+
+ static constexpr int DIGIT_HEIGHT = 64;
+ static constexpr int DIGIT_WIDTH = 40;
+ static constexpr int COLON_WIDTH = DIGIT_WIDTH / 2;
+ static constexpr int TIME_WIDTH = (DIGIT_WIDTH * 4) + COLON_WIDTH;
+
+ if (clockTex.h < DIGIT_HEIGHT || clockTex.w < (10 * DIGIT_WIDTH + COLON_WIDTH)) {
+ ALOGE("Clock texture is too small; abandoning boot animation clock");
+ mClockEnabled = false;
+ return;
+ }
+
+ time_t rawtime;
+ time(&rawtime);
+ struct tm* timeInfo = localtime(&rawtime);
+
+ char timeBuff[TIME_LENGTH];
+ size_t length = strftime(timeBuff, TIME_LENGTH, TIME_FORMAT, timeInfo);
+
+ if (length != TIME_LENGTH - 1) {
+ ALOGE("Couldn't format time; abandoning boot animation clock");
+ mClockEnabled = false;
+ return;
+ }
+
+ glEnable(GL_BLEND); // Allow us to draw on top of the animation
+ glBindTexture(GL_TEXTURE_2D, clockTex.name);
+
+ int xPos = (mWidth - TIME_WIDTH) / 2;
+ int cropRect[4] = { 0, DIGIT_HEIGHT, DIGIT_WIDTH, -DIGIT_HEIGHT };
+
+ for (int i = 0; i < TIME_LENGTH - 1; i++) {
+ char c = timeBuff[i];
+ int width = DIGIT_WIDTH;
+ int pos = c - '0'; // Position in the character list
+ if (pos < 0 || pos > 10) {
+ continue;
+ }
+ if (c == ':') {
+ width = COLON_WIDTH;
+ }
+
+ // Crop the texture to only the pixels in the current glyph
+ int left = pos * DIGIT_WIDTH;
+ cropRect[0] = left;
+ cropRect[2] = width;
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
+
+ glDrawTexiOES(xPos, yPos, 0, width, DIGIT_HEIGHT);
+
+ xPos += width;
+ }
+
+ glDisable(GL_BLEND); // Return to the animation's default behaviour
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
bool BootAnimation::movie()
{
String8 desString;
@@ -477,7 +539,12 @@
if (endl == NULL) break;
String8 line(s, endl - s);
const char* l = line.string();
- int fps, width, height, count, pause;
+ int fps = 0;
+ int width = 0;
+ int height = 0;
+ int count = 0;
+ int pause = 0;
+ int clockPosY = -1;
char path[ANIM_ENTRY_NAME_MAX];
char color[7] = "000000"; // default to black if unspecified
@@ -487,14 +554,15 @@
animation.width = width;
animation.height = height;
animation.fps = fps;
- }
- else if (sscanf(l, " %c %d %d %s #%6s", &pathType, &count, &pause, path, color) >= 4) {
- // ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s", pathType, count, pause, path, color);
+ } else if (sscanf(l, " %c %d %d %s #%6s %d",
+ &pathType, &count, &pause, path, color, &clockPosY) >= 4) {
+ // ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPosY=%d", pathType, count, pause, path, color, clockPosY);
Animation::Part part;
part.playUntilComplete = pathType == 'c';
part.count = count;
part.pause = pause;
part.path = path;
+ part.clockPosY = clockPosY;
part.audioFile = NULL;
if (!parseColor(color, part.backgroundColor)) {
ALOGE("> invalid color '#%s'", color);
@@ -556,6 +624,8 @@
mZip->endIteration(cookie);
+ // Blend required to draw time on top of animation frames.
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
@@ -569,6 +639,12 @@
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ bool clockTextureInitialized = false;
+ if (mClockEnabled) {
+ clockTextureInitialized = (initTexture(&mClock, mAssets, "images/clock64.png") == NO_ERROR);
+ mClockEnabled = clockTextureInitialized;
+ }
+
const int xc = (mWidth - animation.width) / 2;
const int yc = ((mHeight - animation.height) / 2);
nsecs_t frameDuration = s2ns(1) / animation.fps;
@@ -629,6 +705,10 @@
// which is equivalent to mHeight - (yc + animation.height)
glDrawTexiOES(xc, mHeight - (yc + animation.height),
0, animation.width, animation.height);
+ if (mClockEnabled && part.clockPosY >= 0) {
+ drawTime(mClock, part.clockPosY);
+ }
+
eglSwapBuffers(mDisplay, mSurface);
nsecs_t now = systemTime();
@@ -665,6 +745,10 @@
}
}
+ if (clockTextureInitialized) {
+ glDeleteTextures(1, &mClock.name);
+ }
+
return false;
}
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index f968b25..83e2b38 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -67,8 +67,10 @@
}
};
struct Part {
- int count;
- int pause;
+ int count; // The number of times this part should repeat, 0 for infinite
+ int pause; // The number of frames to pause for at the end of this part
+ int clockPosY; // The y position of the clock, in pixels, from the bottom of the
+ // display (the clock is centred horizontally). -1 to disable the clock
String8 path;
SortedVector<Frame> frames;
bool playUntilComplete;
@@ -86,6 +88,7 @@
bool android();
bool readFile(const char* name, String8& outString);
bool movie();
+ void drawTime(const Texture& clockTex, const int yPos);
void checkExit();
@@ -93,6 +96,7 @@
sp<AudioPlayer> mAudioPlayer;
AssetManager mAssets;
Texture mAndroid[2];
+ Texture mClock;
int mWidth;
int mHeight;
EGLDisplay mDisplay;
@@ -101,6 +105,7 @@
sp<SurfaceControl> mFlingerSurfaceControl;
sp<Surface> mFlingerSurface;
ZipFileRO *mZip;
+ bool mClockEnabled;
};
// ---------------------------------------------------------------------------
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..6b67b95 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6177,14 +6177,24 @@
/**
* Enable or disable virtual reality (VR) mode.
*
- * <p>VR mode is a hint to Android system services to switch to modes optimized for
- * high-performance stereoscopic rendering.</p>
+ * <p>VR mode is a hint to Android system services to switch to a mode optimized for
+ * high-performance stereoscopic rendering. This mode will be enabled while this Activity has
+ * focus.</p>
*
* @param enabled {@code true} to enable this mode.
+ * @param requestedComponent the name of the component to use as a
+ * {@link android.service.vr.VrListenerService} while VR mode is enabled.
+ *
+ * @throws android.content.pm.PackageManager.NameNotFoundException;
*/
- public void setVrMode(boolean enabled) {
+ public void setVrModeEnabled(boolean enabled, @NonNull ComponentName requestedComponent)
+ throws PackageManager.NameNotFoundException {
try {
- ActivityManagerNative.getDefault().setVrMode(mToken, enabled);
+ if (ActivityManagerNative.getDefault().setVrMode(mToken, enabled, requestedComponent)
+ != 0) {
+ throw new PackageManager.NameNotFoundException(
+ requestedComponent.flattenToString());
+ }
} catch (RemoteException e) {
// pass
}
@@ -6599,7 +6609,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..2f6907e 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 {
@@ -1544,6 +1575,7 @@
Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
dest.writeInt(numActivities);
dest.writeInt(numRunning);
+ dest.writeInt(isDockable ? 1 : 0);
}
public void readFromParcel(Parcel source) {
@@ -1559,6 +1591,7 @@
description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
numActivities = source.readInt();
numRunning = source.readInt();
+ isDockable = source.readInt() != 0;
}
public static final Creator<RunningTaskInfo> CREATOR = new Creator<RunningTaskInfo>() {
@@ -3340,6 +3373,15 @@
}
}
+ /** {@hide} */
+ public boolean isVrModePackageEnabled(ComponentName component) {
+ try {
+ return ActivityManagerNative.getDefault().isVrModePackageEnabled(component);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Perform a system dump of various state associated with the given application
* package name. This call blocks while the dump is being performed, so should
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b264e8e..6fbb430 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -792,8 +792,9 @@
if (hasBounds) {
bounds = Rect.CREATOR.createFromParcel(data);
}
- moveTaskToDockedStack(taskId, createMode, toTop, animate, bounds);
+ boolean res = moveTaskToDockedStack(taskId, createMode, toTop, animate, bounds);
reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
return true;
}
@@ -822,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;
@@ -2887,8 +2902,18 @@
data.enforceInterface(IActivityManager.descriptor);
final IBinder token = data.readStrongBinder();
final boolean enable = data.readInt() == 1;
- setVrMode(token, enable);
+ final ComponentName packageName = ComponentName.CREATOR.createFromParcel(data);
+ int res = setVrMode(token, enable, packageName);
reply.writeNoException();
+ reply.writeInt(res);
+ return true;
+ }
+ case IS_VR_PACKAGE_ENABLED_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final ComponentName packageName = ComponentName.CREATOR.createFromParcel(data);
+ boolean res = isVrModePackageEnabled(packageName);
+ reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
return true;
}
case IS_APP_FOREGROUND_TRANSACTION: {
@@ -3809,7 +3834,7 @@
reply.recycle();
}
@Override
- public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
+ public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
Rect initialBounds) throws RemoteException
{
Parcel data = Parcel.obtain();
@@ -3827,8 +3852,10 @@
}
mRemote.transact(MOVE_TASK_TO_DOCKED_STACK_TRANSACTION, data, reply, 0);
reply.readException();
+ boolean res = reply.readInt() > 0;
data.recycle();
reply.recycle();
+ return res;
}
@Override
public boolean moveTopActivityToPinnedStack(int stackId, Rect r)
@@ -3911,6 +3938,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
{
@@ -6205,16 +6257,34 @@
return res;
}
- public void setVrMode(IBinder token, boolean enabled) throws RemoteException {
+ public int setVrMode(IBinder token, boolean enabled, ComponentName packageName)
+ throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
data.writeInt(enabled ? 1 : 0);
+ packageName.writeToParcel(data, 0);
mRemote.transact(SET_VR_MODE_TRANSACTION, data, reply, 0);
reply.readException();
+ int res = reply.readInt();
data.recycle();
reply.recycle();
+ return res;
+ }
+
+ public boolean isVrModePackageEnabled(ComponentName packageName)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ packageName.writeToParcel(data, 0);
+ mRemote.transact(IS_VR_PACKAGE_ENABLED_TRANSACTION, data, reply, 0);
+ reply.readException();
+ int res = reply.readInt();
+ data.recycle();
+ reply.recycle();
+ return res == 1;
}
@Override
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e41b792..a452d20 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -113,6 +113,7 @@
import com.android.internal.os.RuntimeInit;
import com.android.internal.os.SamplingProfilerIntegration;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.org.conscrypt.OpenSSLSocketImpl;
import com.android.org.conscrypt.TrustedCertificateStore;
@@ -193,7 +194,7 @@
private ContextImpl mSystemContext;
- static IPackageManager sPackageManager;
+ static volatile IPackageManager sPackageManager;
final ApplicationThread mAppThread = new ApplicationThread();
final Looper mLooper = Looper.myLooper();
@@ -218,7 +219,7 @@
// set of instantiated backup agents, keyed by package name
final ArrayMap<String, BackupAgent> mBackupAgents = new ArrayMap<String, BackupAgent>();
/** Reference to singleton {@link ActivityThread} */
- private static ActivityThread sCurrentActivityThread;
+ private static volatile ActivityThread sCurrentActivityThread;
Instrumentation mInstrumentation;
String mInstrumentationPackageName = null;
String mInstrumentationAppDir = null;
@@ -296,7 +297,7 @@
final GcIdler mGcIdler = new GcIdler();
boolean mGcIdlerScheduled = false;
- static Handler sMainThreadHandler; // set once in main()
+ static volatile Handler sMainThreadHandler; // set once in main()
Bundle mCoreSettings = null;
@@ -1788,7 +1789,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 +1800,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;
}
@@ -3345,6 +3360,18 @@
}
r.activity.performResume();
+ // If there is a pending local relaunch that was requested when the activity was
+ // paused, it will put the activity into paused state when it finally happens.
+ // Since the activity resumed before being relaunched, we don't want that to happen,
+ // so we need to clear the request to relaunch paused.
+ for (int i = mRelaunchingActivities.size() - 1; i >= 0; i--) {
+ final ActivityClientRecord relaunching = mRelaunchingActivities.get(i);
+ if (relaunching.token == r.token
+ && relaunching.onlyLocalRequest && relaunching.startsNotResumed) {
+ relaunching.startsNotResumed = false;
+ }
+ }
+
EventLog.writeEvent(LOG_AM_ON_RESUME_CALLED, UserHandle.myUserId(),
r.activity.getComponentName().getClassName(), reason);
@@ -3576,6 +3603,7 @@
private void handlePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport, int seq) {
ActivityClientRecord r = mActivities.get(token);
+ if (DEBUG_ORDER) Slog.d(TAG, "handlePauseActivity " + r + ", seq: " + seq);
if (!checkAndUpdateLifecycleSeq(seq, r, "pauseActivity")) {
return;
}
@@ -4230,6 +4258,7 @@
synchronized (mResourcesManager) {
for (int i=0; i<mRelaunchingActivities.size(); i++) {
ActivityClientRecord r = mRelaunchingActivities.get(i);
+ if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: " + this + ", trying: " + r);
if (r.token == token) {
target = r;
if (pendingResults != null) {
@@ -4260,14 +4289,19 @@
}
if (target == null) {
+ if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: target is null, fromServer:"
+ + fromServer);
target = new ActivityClientRecord();
target.token = token;
target.pendingResults = pendingResults;
target.pendingIntents = pendingNewIntents;
target.mPreserveWindow = preserveWindow;
if (!fromServer) {
- ActivityClientRecord existing = mActivities.get(token);
+ final ActivityClientRecord existing = mActivities.get(token);
+ if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: " + existing);
if (existing != null) {
+ if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: paused= "
+ + existing.paused);;
target.startsNotResumed = existing.paused;
target.overrideConfig = existing.overrideConfig;
}
@@ -4290,8 +4324,8 @@
target.pendingConfigChanges |= configChanges;
target.relaunchSeq = getLifecycleSeq();
}
- if (DEBUG_ORDER) Slog.d(TAG, "relaunchActivity " + ActivityThread.this
- + " operation received seq: " + target.relaunchSeq);
+ if (DEBUG_ORDER) Slog.d(TAG, "relaunchActivity " + ActivityThread.this + ", target "
+ + target + " operation received seq: " + target.relaunchSeq);
}
private void handleRelaunchActivity(ActivityClientRecord tmp) {
@@ -4730,29 +4764,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() {
@@ -4846,11 +4938,15 @@
Os.fchmod(fd, permissions);
Os.fchown(fd, appInfo.uid, appInfo.uid);
} catch (ErrnoException e) {
- Log.v(TAG, "Unable to create jit profile file " + profileFile, e);
+ Log.v(TAG, "Unable to create jit profile file "
+ + profileFile + ": " + e.getMessage());
try {
Os.unlink(profileFile.getAbsolutePath());
} catch (ErrnoException unlinkErr) {
- Log.v(TAG, "Unable to unlink jit profile file " + profileFile, unlinkErr);
+ if (unlinkErr.errno != OsConstants.ENOENT) {
+ Log.v(TAG, "Unable to unlink jit profile file "
+ + profileFile + ": " + unlinkErr.getMessage());
+ }
}
return;
} finally {
@@ -4886,6 +4982,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);
@@ -5166,9 +5265,8 @@
// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
if (!data.restrictedBackupMode) {
- List<ProviderInfo> providers = data.providers;
- if (providers != null) {
- installContentProviders(app, providers);
+ if (!ArrayUtils.isEmpty(data.providers)) {
+ installContentProviders(app, data.providers);
// For process that contains content providers, we want to
// ensure that the JIT is enabled "at some point".
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index b569416..455f869 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -201,6 +201,7 @@
try {
mService.remove(null, this);
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
synchronized (AlarmManager.class) {
@@ -656,6 +657,7 @@
mService.set(mPackageName, type, triggerAtMillis, windowMillis, intervalMillis, flags,
operation, recipientWrapper, listenerTag, workSource, alarmClock);
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
@@ -886,6 +888,7 @@
try {
mService.remove(operation, null);
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
@@ -926,6 +929,7 @@
try {
mService.setTime(millis);
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
@@ -965,6 +969,7 @@
try {
mService.setTimeZone(timeZone);
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
@@ -973,7 +978,7 @@
try {
return mService.getNextWakeFromIdleTime();
} catch (RemoteException ex) {
- return Long.MAX_VALUE;
+ throw ex.rethrowFromSystemServer();
}
}
@@ -1005,7 +1010,7 @@
try {
return mService.getNextAlarmClock(userId);
} catch (RemoteException ex) {
- return null;
+ throw ex.rethrowFromSystemServer();
}
}
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..0b44925 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -275,7 +275,7 @@
public List<PermissionInfo> queryPermissionsByGroup(String group, int flags)
throws NameNotFoundException {
try {
- List<PermissionInfo> pi = mPM.queryPermissionsByGroup(group, flags);
+ List<PermissionInfo> pi = mPM.queryPermissionsByGroup(group, flags).getList();
if (pi != null) {
return pi;
}
@@ -304,7 +304,7 @@
@Override
public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
try {
- return mPM.getAllPermissionGroups(flags);
+ return mPM.getAllPermissionGroups(flags).getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -441,7 +441,12 @@
@Override
public FeatureInfo[] getSystemAvailableFeatures() {
try {
- return mPM.getSystemAvailableFeatures();
+ final List<FeatureInfo> list = mPM.getSystemAvailableFeatures().getList();
+ final FeatureInfo[] res = new FeatureInfo[list.size()];
+ for (int i = 0; i < res.length; i++) {
+ res[i] = list.get(i);
+ }
+ return res;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -772,7 +777,7 @@
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
flags,
- userId);
+ userId).getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -802,9 +807,10 @@
}
try {
- return mPM.queryIntentActivityOptions(caller, specifics,
- specificTypes, intent, intent.resolveTypeIfNeeded(resolver),
- flags, mContext.getUserId());
+ return mPM
+ .queryIntentActivityOptions(caller, specifics, specificTypes, intent,
+ intent.resolveTypeIfNeeded(resolver), flags, mContext.getUserId())
+ .getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -820,7 +826,7 @@
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
flags,
- userId);
+ userId).getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -851,7 +857,7 @@
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
flags,
- userId);
+ userId).getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -867,7 +873,8 @@
Intent intent, int flags, int userId) {
try {
return mPM.queryIntentContentProviders(intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()), flags, userId);
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()), flags, userId)
+ .getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -926,7 +933,7 @@
public List<InstrumentationInfo> queryInstrumentation(
String targetPackage, int flags) {
try {
- return mPM.queryInstrumentation(targetPackage, flags);
+ return mPM.queryInstrumentation(targetPackage, flags).getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1093,6 +1100,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 +1129,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 +1550,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();
}
@@ -1561,7 +1579,7 @@
@Override
public List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName) {
try {
- return mPM.getIntentFilterVerifications(packageName);
+ return mPM.getIntentFilterVerifications(packageName).getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1570,7 +1588,7 @@
@Override
public List<IntentFilter> getAllIntentFilters(String packageName) {
try {
- return mPM.getAllIntentFilters(packageName);
+ return mPM.getAllIntentFilters(packageName).getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1881,31 +1899,21 @@
throw e.rethrowFromSystemServer();
}
}
+
@Override
public void addPackageToPreferred(String packageName) {
- try {
- mPM.addPackageToPreferred(packageName);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ Log.w(TAG, "addPackageToPreferred() is a no-op");
}
@Override
public void removePackageFromPreferred(String packageName) {
- try {
- mPM.removePackageFromPreferred(packageName);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ Log.w(TAG, "removePackageFromPreferred() is a no-op");
}
@Override
public List<PackageInfo> getPreferredPackages(int flags) {
- try {
- return mPM.getPreferredPackages(flags);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ Log.w(TAG, "getPreferredPackages() is a no-op");
+ return Collections.emptyList();
}
@Override
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 47eec8b..e76f991 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -396,9 +396,11 @@
/**
* Try our best to migrate all files from source to target that match
- * requested prefix. Return false if we have any trouble migrating.
+ * requested prefix.
+ *
+ * @return the number of files moved, or -1 if there was trouble.
*/
- private static boolean migrateFiles(File sourceDir, File targetDir, final String prefix) {
+ private static int migrateFiles(File sourceDir, File targetDir, final String prefix) {
final File[] sourceFiles = FileUtils.listFilesOrEmpty(sourceDir, new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
@@ -406,7 +408,7 @@
}
});
- boolean res = true;
+ int res = 0;
for (File sourceFile : sourceFiles) {
final File targetFile = new File(targetDir, sourceFile.getName());
Log.d(TAG, "Migrating " + sourceFile + " to " + targetFile);
@@ -416,9 +418,12 @@
if (!sourceFile.delete()) {
throw new IOException("Failed to clean up " + sourceFile);
}
+ if (res != -1) {
+ res++;
+ }
} catch (IOException e) {
Log.w(TAG, "Failed to migrate " + sourceFile + ": " + e);
- res = false;
+ res = -1;
}
}
return res;
@@ -430,12 +435,17 @@
final File source = sourceContext.getSharedPreferencesPath(name);
final File target = getSharedPreferencesPath(name);
- // Evict any in-memory caches for either location
- final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked();
- cache.remove(source);
- cache.remove(target);
-
- return migrateFiles(source.getParentFile(), target.getParentFile(), source.getName());
+ final int res = migrateFiles(source.getParentFile(), target.getParentFile(),
+ source.getName());
+ if (res > 0) {
+ // We moved at least one file, so evict any in-memory caches for
+ // either location
+ final ArrayMap<File, SharedPreferencesImpl> cache =
+ getSharedPreferencesCacheLocked();
+ cache.remove(source);
+ cache.remove(target);
+ }
+ return res != -1;
}
}
@@ -675,7 +685,8 @@
synchronized (ContextImpl.class) {
final File source = sourceContext.getDatabasePath(name);
final File target = getDatabasePath(name);
- return migrateFiles(source.getParentFile(), target.getParentFile(), source.getName());
+ return migrateFiles(source.getParentFile(), target.getParentFile(),
+ source.getName()) != -1;
}
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 4bfd049..eadf497 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -33,6 +33,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.ProviderInfo;
import android.content.pm.UserInfo;
@@ -143,7 +144,7 @@
public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException;
public void moveTaskBackwards(int task) throws RemoteException;
public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException;
- public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
+ public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
Rect initialBounds) throws RemoteException;
public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) throws RemoteException;
public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode,
@@ -171,6 +172,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;
@@ -589,7 +600,10 @@
public void enterPictureInPicture(IBinder token) throws RemoteException;
- public void setVrMode(IBinder token, boolean enabled) throws RemoteException;
+ public int setVrMode(IBinder token, boolean enabled, ComponentName packageName)
+ throws RemoteException;
+
+ public boolean isVrModePackageEnabled(ComponentName packageName) throws RemoteException;
public boolean isAppForeground(int uid) throws RemoteException;
@@ -982,4 +996,6 @@
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;
+ int IS_VR_PACKAGE_ENABLED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 371;
}
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/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 5697924..2c270fc 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -61,7 +61,7 @@
StatusBarNotification[] getActiveNotifications(String callingPkg);
StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count);
- void registerListener(in INotificationListener listener, in ComponentName component, int userid);
+ void registerListener(in INotificationListener listener, in ComponentName component, int userid, boolean asRanker);
void unregisterListener(in INotificationListener listener, int userid);
void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
@@ -80,7 +80,7 @@
void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
void setInterruptionFilter(String pkg, int interruptionFilter);
- void setImportanceFromAssistant(in INotificationListener token, String key, int importance, CharSequence explanation);
+ void setImportanceFromRankerService(in INotificationListener token, String key, int importance, CharSequence explanation);
ComponentName getEffectsSuppressor();
boolean matchesCallFilter(in Bundle extras);
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/Notification.java b/core/java/android/app/Notification.java
index 2c34371..d8f0ac5 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2994,7 +2994,6 @@
contentView.setViewVisibility(R.id.chronometer, View.GONE);
contentView.setViewVisibility(R.id.header_sub_text, View.GONE);
contentView.setViewVisibility(R.id.header_content_info, View.GONE);
- contentView.setViewVisibility(R.id.number_of_children, View.GONE);
contentView.setViewVisibility(R.id.sub_text_divider, View.GONE);
contentView.setViewVisibility(R.id.content_info_divider, View.GONE);
contentView.setViewVisibility(R.id.time_divider, View.GONE);
@@ -3095,7 +3094,6 @@
private void bindNotificationHeader(RemoteViews contentView) {
bindSmallIcon(contentView);
- bindChildCountColor(contentView);
bindHeaderAppName(contentView);
bindHeaderSubText(contentView);
bindContentInfo(contentView);
@@ -3104,10 +3102,6 @@
bindProfileBadge(contentView);
}
- private void bindChildCountColor(RemoteViews contentView) {
- contentView.setTextColor(R.id.number_of_children, resolveColor());
- }
-
private void bindContentInfo(RemoteViews contentView) {
boolean visible = false;
if (mN.extras.getCharSequence(EXTRA_INFO_TEXT) != null) {
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index b6448ee..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];
}
};
-
}
/**
@@ -890,9 +903,8 @@
final List<StatusBarNotification> list = parceledList.getList();
return list.toArray(new StatusBarNotification[list.size()]);
} catch (RemoteException e) {
- Log.e(TAG, "Unable to talk to notification manager. Woe!", e);
+ throw e.rethrowFromSystemServer();
}
- return new StatusBarNotification[0];
}
/**
@@ -913,9 +925,8 @@
try {
return zenModeToInterruptionFilter(service.getZenMode());
} catch (RemoteException e) {
- Log.e(TAG, "Unable to talk to notification manager. Woe!", e);
+ throw e.rethrowFromSystemServer();
}
- return INTERRUPTION_FILTER_UNKNOWN;
}
/**
@@ -936,7 +947,7 @@
try {
service.setInterruptionFilter(mContext.getOpPackageName(), interruptionFilter);
} catch (RemoteException e) {
- Log.e(TAG, "Unable to talk to notification manager. Woe!", e);
+ throw e.rethrowFromSystemServer();
}
}
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/SearchManager.java b/core/java/android/app/SearchManager.java
index 9e32164..ac4abf5 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -686,8 +686,7 @@
try {
return mService.getGlobalSearchActivities();
} catch (RemoteException ex) {
- Log.e(TAG, "getGlobalSearchActivities() failed: " + ex);
- return null;
+ throw ex.rethrowFromSystemServer();
}
}
@@ -698,8 +697,7 @@
try {
return mService.getGlobalSearchActivity();
} catch (RemoteException ex) {
- Log.e(TAG, "getGlobalSearchActivity() failed: " + ex);
- return null;
+ throw ex.rethrowFromSystemServer();
}
}
@@ -716,8 +714,7 @@
try {
return mService.getWebSearchActivity();
} catch (RemoteException ex) {
- Log.e(TAG, "getWebSearchActivity() failed: " + ex);
- return null;
+ throw ex.rethrowFromSystemServer();
}
}
@@ -850,8 +847,7 @@
try {
return mService.getSearchableInfo(componentName);
} catch (RemoteException ex) {
- Log.e(TAG, "getSearchableInfo() failed: " + ex);
- return null;
+ throw ex.rethrowFromSystemServer();
}
}
@@ -935,8 +931,7 @@
try {
return mService.getSearchablesInGlobalSearch();
} catch (RemoteException e) {
- Log.e(TAG, "getSearchablesInGlobalSearch() failed: " + e);
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -958,8 +953,7 @@
}
return intent;
} catch (RemoteException re) {
- Log.e(TAG, "getAssistIntent() failed: " + re);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -977,7 +971,7 @@
}
mService.launchAssist(args);
} catch (RemoteException re) {
- Log.e(TAG, "launchAssist() failed: " + re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -995,8 +989,7 @@
}
return mService.launchLegacyAssist(hint, userHandle, args);
} catch (RemoteException re) {
- Log.e(TAG, "launchAssist() failed: " + re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index b899116..e57a9b5 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -123,8 +123,7 @@
svc.disable(what, mToken, mContext.getPackageName());
}
} catch (RemoteException ex) {
- // system process is dead anyway.
- throw new RuntimeException(ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -141,8 +140,7 @@
svc.disable2(what, mToken, mContext.getPackageName());
}
} catch (RemoteException ex) {
- // system process is dead anyway.
- throw new RuntimeException(ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -156,8 +154,7 @@
svc.expandNotificationsPanel();
}
} catch (RemoteException ex) {
- // system process is dead anyway.
- throw new RuntimeException(ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -171,8 +168,7 @@
svc.collapsePanels();
}
} catch (RemoteException ex) {
- // system process is dead anyway.
- throw new RuntimeException(ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -193,8 +189,7 @@
svc.expandSettingsPanel(subPanel);
}
} catch (RemoteException ex) {
- // system process is dead anyway.
- throw new RuntimeException(ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -206,8 +201,7 @@
contentDescription);
}
} catch (RemoteException ex) {
- // system process is dead anyway.
- throw new RuntimeException(ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -218,8 +212,7 @@
svc.removeIcon(slot);
}
} catch (RemoteException ex) {
- // system process is dead anyway.
- throw new RuntimeException(ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -230,8 +223,7 @@
svc.setIconVisibility(slot, visible);
}
} catch (RemoteException ex) {
- // system process is dead anyway.
- throw new RuntimeException(ex);
+ throw ex.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 307c3eb..b1c5fd8 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -226,7 +226,7 @@
SYSTEM_SERVICE_NAMES.put(android.text.ClipboardManager.class, Context.CLIPBOARD_SERVICE);
registerService(Context.CONNECTIVITY_SERVICE, ConnectivityManager.class,
- new StaticOuterContextServiceFetcher<ConnectivityManager>() {
+ new StaticApplicationContextServiceFetcher<ConnectivityManager>() {
@Override
public ConnectivityManager createService(Context context) {
IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
@@ -840,22 +840,21 @@
}
/**
- * Like StaticServiceFetcher, creates only one instance of the service per process, but when
- * creating the service for the first time, passes it the outer context of the creating
- * component.
+ * Like StaticServiceFetcher, creates only one instance of the service per application, but when
+ * creating the service for the first time, passes it the application context of the creating
+ * application.
*
- * TODO: Is this safe in the case where multiple applications share the same process?
* TODO: Delete this once its only user (ConnectivityManager) is known to work well in the
* case where multiple application components each have their own ConnectivityManager object.
*/
- static abstract class StaticOuterContextServiceFetcher<T> implements ServiceFetcher<T> {
+ static abstract class StaticApplicationContextServiceFetcher<T> implements ServiceFetcher<T> {
private T mCachedInstance;
@Override
public final T getService(ContextImpl ctx) {
- synchronized (StaticOuterContextServiceFetcher.this) {
+ synchronized (StaticApplicationContextServiceFetcher.this) {
if (mCachedInstance == null) {
- mCachedInstance = createService(ctx.getOuterContext());
+ mCachedInstance = createService(ctx.getApplicationContext());
}
return mCachedInstance;
}
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 56b4249..69e8df8 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -17,6 +17,7 @@
package android.app;
import android.annotation.IntDef;
+import android.annotation.TestApi;
import android.content.Context;
import android.content.res.Configuration;
import android.os.RemoteException;
@@ -158,7 +159,7 @@
try {
mService.enableCarMode(flags);
} catch (RemoteException e) {
- Log.e(TAG, "disableCarMode: RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -181,7 +182,7 @@
try {
mService.disableCarMode(flags);
} catch (RemoteException e) {
- Log.e(TAG, "disableCarMode: RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -200,7 +201,7 @@
try {
return mService.getCurrentModeType();
} catch (RemoteException e) {
- Log.e(TAG, "getCurrentModeType: RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
return Configuration.UI_MODE_TYPE_NORMAL;
@@ -233,7 +234,7 @@
try {
mService.setNightMode(mode);
} catch (RemoteException e) {
- Log.e(TAG, "setNightMode: RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -257,7 +258,7 @@
try {
return mService.getNightMode();
} catch (RemoteException e) {
- Log.e(TAG, "getNightMode: RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
return -1;
@@ -266,13 +267,15 @@
/**
* @return If UI mode is locked or not. When UI mode is locked, calls to change UI mode
* like {@link #enableCarMode(int)} will silently fail.
+ * @hide
*/
+ @TestApi
public boolean isUiModeLocked() {
if (mService != null) {
try {
return mService.isUiModeLocked();
} catch (RemoteException e) {
- Log.e(TAG, "isUiModeLocked: RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
return true;
@@ -286,13 +289,15 @@
* mode will fail silently.
*
* @return {@code true} if night mode is locked or {@code false} otherwise
+ * @hide
*/
+ @TestApi
public boolean isNightModeLocked() {
if (mService != null) {
try {
return mService.isNightModeLocked();
} catch (RemoteException e) {
- Log.e(TAG, "isNightModeLocked: RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
return true;
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index b7e31ab..6bc03f7 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -293,7 +293,7 @@
return null;
}
} catch (RemoteException e) {
- // Ignore
+ throw e.rethrowFromSystemServer();
}
}
if (mWallpaper != null) {
@@ -349,7 +349,7 @@
}
}
} catch (RemoteException e) {
- // Ignore
+ throw e.rethrowFromSystemServer();
}
return null;
}
@@ -691,7 +691,7 @@
Bundle outParams = new Bundle();
return sGlobals.mService.getWallpaper(null, which, outParams, userId);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -720,7 +720,7 @@
return sGlobals.mService.getWallpaperInfo();
}
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -844,7 +844,7 @@
}
}
} catch (RemoteException e) {
- // Ignore
+ throw e.rethrowFromSystemServer();
}
return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
}
@@ -950,7 +950,7 @@
}
}
} catch (RemoteException e) {
- // Ignore
+ throw e.rethrowFromSystemServer();
}
return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
}
@@ -1067,7 +1067,7 @@
}
}
} catch (RemoteException e) {
- // Ignore
+ throw e.rethrowFromSystemServer();
}
return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
@@ -1088,7 +1088,7 @@
String name = "res:" + resources.getResourceName(resid);
return sGlobals.mService.hasNamedWallpaper(name);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1114,8 +1114,7 @@
try {
return sGlobals.mService.getWidthHint();
} catch (RemoteException e) {
- // Shouldn't happen!
- return 0;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1141,8 +1140,7 @@
try {
return sGlobals.mService.getHeightHint();
} catch (RemoteException e) {
- // Shouldn't happen!
- return 0;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1203,7 +1201,7 @@
mContext.getOpPackageName());
}
} catch (RemoteException e) {
- // Ignore
+ throw e.rethrowFromSystemServer();
}
}
@@ -1224,7 +1222,7 @@
sGlobals.mService.setDisplayPadding(padding, mContext.getOpPackageName());
}
} catch (RemoteException e) {
- // Ignore
+ throw e.rethrowFromSystemServer();
}
}
@@ -1245,7 +1243,7 @@
windowToken, x, y);
//Log.v(TAG, "...app returning after sending display offset!");
} catch (RemoteException e) {
- // Ignore.
+ throw e.rethrowFromSystemServer();
}
}
@@ -1274,7 +1272,7 @@
try {
sGlobals.mService.clearWallpaper(mContext.getOpPackageName(), which, userId);
} catch (RemoteException e) {
- // Ignore
+ throw e.rethrowFromSystemServer();
}
}
@@ -1296,9 +1294,8 @@
sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName());
return true;
} catch (RemoteException e) {
- // Ignore
+ throw e.rethrowFromSystemServer();
}
- return false;
}
/**
@@ -1321,7 +1318,7 @@
windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep);
//Log.v(TAG, "...app returning after sending offsets!");
} catch (RemoteException e) {
- // Ignore.
+ throw e.rethrowFromSystemServer();
}
}
@@ -1359,7 +1356,7 @@
windowToken, action, x, y, z, extras, false);
//Log.v(TAG, "...app returning after sending offsets!");
} catch (RemoteException e) {
- // Ignore.
+ throw e.rethrowFromSystemServer();
}
}
@@ -1375,7 +1372,7 @@
try {
return sGlobals.mService.isWallpaperSupported(mContext.getOpPackageName());
} catch (RemoteException e) {
- // Ignore
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -1395,7 +1392,7 @@
try {
return sGlobals.mService.isWallpaperSettingAllowed(mContext.getOpPackageName());
} catch (RemoteException e) {
- // Ignore
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -1416,7 +1413,7 @@
WindowManagerGlobal.getWindowSession().setWallpaperPosition(
windowToken, -1, -1, -1, -1);
} catch (RemoteException e) {
- // Ignore.
+ throw e.rethrowFromSystemServer();
}
}
@@ -1436,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
@@ -1497,9 +1513,8 @@
try {
return sGlobals.mService.setLockWallpaperCallback(callback);
} catch (RemoteException e) {
- Log.e(TAG, "Unable to contact wallpaper service");
+ throw e.rethrowFromSystemServer();
}
- return false;
}
// Private completion callback for setWallpaper() synchronization
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 6e29eaa..c4037f8 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -100,9 +100,6 @@
private final IDevicePolicyManager mService;
private final boolean mParentInstance;
- private static final String REMOTE_EXCEPTION_MESSAGE =
- "Failed to talk with device policy manager service";
-
private DevicePolicyManager(Context context, boolean parentInstance) {
this(context,
IDevicePolicyManager.Stub.asInterface(
@@ -347,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.
@@ -989,7 +1048,7 @@
try {
return mService.isAdminActive(admin, userId);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -1004,7 +1063,7 @@
try {
return mService.isRemovingAdmin(admin, userId);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -1029,7 +1088,7 @@
try {
return mService.getActiveAdmins(userId);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -1054,7 +1113,7 @@
try {
return mService.packageHasActiveAdmins(packageName, userId);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -1074,7 +1133,7 @@
try {
mService.removeActiveAdmin(admin, myUserId());
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1093,7 +1152,7 @@
try {
return mService.hasGrantedPolicy(admin, usesPolicy, myUserId());
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -1109,7 +1168,7 @@
try {
return mService.isSeparateProfileChallengeAllowed(userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -1227,7 +1286,7 @@
try {
mService.setPasswordQuality(admin, quality, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1254,7 +1313,7 @@
try {
return mService.getPasswordQuality(admin, userHandle, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return PASSWORD_QUALITY_UNSPECIFIED;
@@ -1291,7 +1350,7 @@
try {
mService.setPasswordMinimumLength(admin, length, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1319,7 +1378,7 @@
try {
return mService.getPasswordMinimumLength(admin, userHandle, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return 0;
@@ -1357,7 +1416,7 @@
try {
mService.setPasswordMinimumUpperCase(admin, length, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1391,7 +1450,7 @@
try {
return mService.getPasswordMinimumUpperCase(admin, userHandle, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return 0;
@@ -1429,7 +1488,7 @@
try {
mService.setPasswordMinimumLowerCase(admin, length, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1463,7 +1522,7 @@
try {
return mService.getPasswordMinimumLowerCase(admin, userHandle, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return 0;
@@ -1500,7 +1559,7 @@
try {
mService.setPasswordMinimumLetters(admin, length, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1533,7 +1592,7 @@
try {
return mService.getPasswordMinimumLetters(admin, userHandle, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return 0;
@@ -1570,7 +1629,7 @@
try {
mService.setPasswordMinimumNumeric(admin, length, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1603,7 +1662,7 @@
try {
return mService.getPasswordMinimumNumeric(admin, userHandle, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return 0;
@@ -1640,7 +1699,7 @@
try {
mService.setPasswordMinimumSymbols(admin, length, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1672,7 +1731,7 @@
try {
return mService.getPasswordMinimumSymbols(admin, userHandle, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return 0;
@@ -1709,7 +1768,7 @@
try {
mService.setPasswordMinimumNonLetter(admin, length, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1742,7 +1801,7 @@
try {
return mService.getPasswordMinimumNonLetter(admin, userHandle, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return 0;
@@ -1780,7 +1839,7 @@
try {
mService.setPasswordHistoryLength(admin, length, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1816,7 +1875,7 @@
try {
mService.setPasswordExpirationTimeout(admin, timeout, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1840,7 +1899,7 @@
try {
return mService.getPasswordExpirationTimeout(admin, myUserId(), mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return 0;
@@ -1864,7 +1923,7 @@
try {
return mService.getPasswordExpiration(admin, myUserId(), mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return 0;
@@ -1893,7 +1952,7 @@
try {
return mService.getPasswordHistoryLength(admin, userHandle, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return 0;
@@ -1931,7 +1990,7 @@
try {
return mService.isActivePasswordSufficient(myUserId(), mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -1951,7 +2010,7 @@
try {
return mService.isProfileActivePasswordSufficientForParent(userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -1988,7 +2047,7 @@
try {
return mService.getCurrentFailedPasswordAttempts(userHandle, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return -1;
@@ -2005,7 +2064,7 @@
try {
return mService.getDoNotAskCredentialsOnBoot();
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -2039,7 +2098,7 @@
try {
mService.setMaximumFailedPasswordsForWipe(admin, num, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2068,7 +2127,7 @@
return mService.getMaximumFailedPasswordsForWipe(
admin, userHandle, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return 0;
@@ -2087,7 +2146,7 @@
return mService.getProfileWithMinimumFailedPasswordsForWipe(
userHandle, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return UserHandle.USER_NULL;
@@ -2155,7 +2214,7 @@
try {
return mService.resetPassword(password, flags);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -2183,7 +2242,7 @@
try {
mService.setMaximumTimeToLock(admin, timeMs, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2212,7 +2271,7 @@
try {
return mService.getMaximumTimeToLock(admin, userHandle, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return 0;
@@ -2235,7 +2294,7 @@
try {
mService.lockNow(mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2272,7 +2331,7 @@
try {
mService.wipeData(flags);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2342,7 +2401,7 @@
}
return mService.setGlobalProxy(admin, hostSpec, exclSpec);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -2370,7 +2429,7 @@
try {
mService.setRecommendedGlobalProxy(admin, proxyInfo);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2386,7 +2445,7 @@
try {
return mService.getGlobalProxyAdmin(myUserId());
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -2515,7 +2574,7 @@
try {
return mService.setStorageEncryption(admin, encrypt);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return ENCRYPTION_STATUS_UNSUPPORTED;
@@ -2535,7 +2594,7 @@
try {
return mService.getStorageEncryption(admin, myUserId());
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -2570,7 +2629,7 @@
try {
return mService.getStorageEncryptionStatus(userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return ENCRYPTION_STATUS_UNSUPPORTED;
@@ -2591,7 +2650,7 @@
try {
return mService.installCaCert(admin, certBuffer);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -2612,7 +2671,7 @@
} catch (CertificateException e) {
Log.w(TAG, "Unable to parse certificate", e);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2640,7 +2699,7 @@
}
}
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
return certs;
@@ -2659,7 +2718,7 @@
mService.uninstallCaCerts(admin, new TrustedCertificateStore().userAliases()
.toArray(new String[0]));
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
}
@@ -2677,7 +2736,7 @@
mService.enforceCanManageCaCerts(admin);
return getCaCertAlias(certBuffer) != null;
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
} catch (CertificateException ce) {
Log.w(TAG, "Could not parse certificate", ce);
}
@@ -2737,7 +2796,7 @@
.getKeySpec(privKey, PKCS8EncodedKeySpec.class).getEncoded();
return mService.installKeyPair(admin, pkcs8Key, pemCert, alias, requestAccess);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
Log.w(TAG, "Failed to obtain private key material", e);
} catch (CertificateException | IOException e) {
@@ -2753,15 +2812,14 @@
* @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 {
return mService.removeKeyPair(admin, alias);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
- return false;
}
/**
@@ -2800,7 +2858,7 @@
try {
mService.setCertInstallerPackage(admin, installerPackage);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2818,7 +2876,7 @@
try {
return mService.getCertInstallerPackage(admin);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -2845,7 +2903,7 @@
try {
return mService.setAlwaysOnVpnPackage(admin, vpnPackage);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -2865,7 +2923,7 @@
try {
return mService.getAlwaysOnVpnPackage(admin);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -2890,7 +2948,7 @@
try {
mService.setCameraDisabled(admin, disabled);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2911,7 +2969,7 @@
try {
return mService.getCameraDisabled(admin, userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -2933,7 +2991,7 @@
try {
return mService.requestBugreport(admin);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -2970,7 +3028,7 @@
try {
mService.setScreenCaptureDisabled(admin, disabled);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2991,7 +3049,7 @@
try {
return mService.getScreenCaptureDisabled(admin, userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -3014,7 +3072,7 @@
try {
mService.setAutoTimeRequired(admin, required);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3027,7 +3085,7 @@
try {
return mService.getAutoTimeRequired();
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -3052,7 +3110,7 @@
try {
mService.setForceEphemeralUsers(admin, forceEphemeralUsers);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3066,7 +3124,7 @@
try {
return mService.getForceEphemeralUsers(admin);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -3115,7 +3173,7 @@
try {
mService.setKeyguardDisabledFeatures(admin, which, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3144,7 +3202,7 @@
try {
return mService.getKeyguardDisabledFeatures(admin, userHandle, mParentInstance);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return KEYGUARD_DISABLE_FEATURES_NONE;
@@ -3159,7 +3217,7 @@
try {
mService.setActiveAdmin(policyReceiver, refreshing, userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3179,7 +3237,7 @@
try {
mService.getRemoveWarning(admin, result, myUserId());
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3194,7 +3252,7 @@
mService.setActivePasswordState(quality, length, letters, uppercase, lowercase,
numbers, symbols, nonletter, userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3207,7 +3265,7 @@
try {
mService.reportFailedPasswordAttempt(userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3220,7 +3278,7 @@
try {
mService.reportSuccessfulPasswordAttempt(userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3233,7 +3291,7 @@
try {
mService.reportFailedFingerprintAttempt(userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3246,7 +3304,7 @@
try {
mService.reportSuccessfulFingerprintAttempt(userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3260,7 +3318,7 @@
try {
mService.reportKeyguardDismissed(userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3274,7 +3332,7 @@
try {
mService.reportKeyguardSecured(userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3327,7 +3385,7 @@
try {
return mService.setDeviceOwner(who, ownerName, userId);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
return false;
@@ -3409,7 +3467,7 @@
try {
return mService.getDeviceOwnerComponent(callingUserOnly);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
return null;
@@ -3428,7 +3486,7 @@
try {
return mService.getDeviceOwnerUserId();
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
return UserHandle.USER_NULL;
@@ -3448,7 +3506,7 @@
try {
mService.clearDeviceOwner(packageName);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
}
@@ -3491,7 +3549,7 @@
try {
return mService.getDeviceOwnerName();
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
return null;
@@ -3544,7 +3602,7 @@
mService.setActiveAdmin(admin, false, myUserId);
return mService.setProfileOwner(admin, ownerName, myUserId);
} catch (RemoteException re) {
- throw new IllegalArgumentException("Couldn't set profile owner.", re);
+ throw re.rethrowFromSystemServer();
}
}
return false;
@@ -3564,7 +3622,7 @@
try {
mService.clearProfileOwner(admin);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
}
@@ -3578,7 +3636,7 @@
try {
return mService.hasUserSetupCompleted();
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
return true;
@@ -3609,8 +3667,7 @@
}
return mService.setProfileOwner(admin, ownerName, userHandle);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- throw new IllegalArgumentException("Couldn't set profile owner.", re);
+ throw re.rethrowFromSystemServer();
}
}
return false;
@@ -3638,7 +3695,7 @@
try {
return mService.setDeviceOwnerLockScreenInfo(admin, info);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
return false;
@@ -3652,7 +3709,7 @@
try {
return mService.getDeviceOwnerLockScreenInfo();
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
return null;
@@ -3680,7 +3737,7 @@
try {
return mService.setPackagesSuspended(admin, packageNames, suspended);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
return packageNames;
@@ -3699,7 +3756,7 @@
try {
return mService.getPackageSuspended(admin, packageName);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -3718,7 +3775,7 @@
try {
mService.setProfileEnabled(admin);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3739,7 +3796,7 @@
try {
mService.setProfileName(admin, profileName);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3759,7 +3816,7 @@
return profileOwner != null
&& profileOwner.getPackageName().equals(packageName);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
return false;
@@ -3785,9 +3842,7 @@
try {
return mService.getProfileOwner(userId);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- throw new IllegalArgumentException(
- "Requested profile owner for invalid userId", re);
+ throw re.rethrowFromSystemServer();
}
}
return null;
@@ -3804,9 +3859,7 @@
try {
return mService.getProfileOwnerName(Process.myUserHandle().getIdentifier());
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- throw new IllegalArgumentException(
- "Requested profile owner for invalid userId", re);
+ throw re.rethrowFromSystemServer();
}
}
return null;
@@ -3825,9 +3878,7 @@
try {
return mService.getProfileOwnerName(userId);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- throw new IllegalArgumentException(
- "Requested profile owner for invalid userId", re);
+ throw re.rethrowFromSystemServer();
}
}
return null;
@@ -3856,7 +3907,7 @@
try {
mService.addPersistentPreferredActivity(admin, filter, activity);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3877,7 +3928,7 @@
try {
mService.clearPackagePersistentPreferredActivities(admin, packageName);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3903,7 +3954,7 @@
try {
mService.setApplicationRestrictionsManagingPackage(admin, packageName);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -3921,7 +3972,7 @@
try {
return mService.getApplicationRestrictionsManagingPackage(admin);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -3937,7 +3988,7 @@
try {
return mService.isCallerApplicationRestrictionsManagingPackage();
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -3982,7 +4033,7 @@
try {
mService.setApplicationRestrictions(admin, packageName, settings);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -4012,7 +4063,7 @@
try {
mService.setTrustAgentConfiguration(admin, target, configuration);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -4043,7 +4094,7 @@
try {
return mService.getTrustAgentConfiguration(admin, agent, userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return new ArrayList<PersistableBundle>(); // empty list
@@ -4064,7 +4115,7 @@
try {
mService.setCrossProfileCallerIdDisabled(admin, disabled);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -4083,7 +4134,7 @@
try {
return mService.getCrossProfileCallerIdDisabled(admin);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -4100,7 +4151,7 @@
try {
return mService.getCrossProfileCallerIdDisabledForUser(userHandle.getIdentifier());
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -4122,7 +4173,7 @@
try {
mService.setCrossProfileContactsSearchDisabled(admin, disabled);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -4141,7 +4192,7 @@
try {
return mService.getCrossProfileContactsSearchDisabled(admin);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -4160,7 +4211,7 @@
return mService
.getCrossProfileContactsSearchDisabledForUser(userHandle.getIdentifier());
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -4178,7 +4229,7 @@
mService.startManagedQuickContact(actualLookupKey, actualContactId,
isContactIdIgnored, directoryId, originalIntent);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -4212,7 +4263,7 @@
try {
mService.setBluetoothContactSharingDisabled(admin, disabled);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -4234,7 +4285,7 @@
try {
return mService.getBluetoothContactSharingDisabled(admin);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return true;
@@ -4254,7 +4305,7 @@
return mService.getBluetoothContactSharingDisabledForUser(userHandle
.getIdentifier());
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return true;
@@ -4276,7 +4327,7 @@
try {
mService.addCrossProfileIntentFilter(admin, filter, flags);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -4292,7 +4343,7 @@
try {
mService.clearCrossProfileIntentFilters(admin);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -4324,7 +4375,7 @@
try {
return mService.setPermittedAccessibilityServices(admin, packageNames);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -4344,7 +4395,7 @@
try {
return mService.getPermittedAccessibilityServices(admin);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -4367,7 +4418,7 @@
return mService.isAccessibilityServicePermittedByAdmin(admin, packageName,
userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -4391,7 +4442,7 @@
try {
return mService.getPermittedAccessibilityServicesForUser(userId);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -4425,7 +4476,7 @@
try {
return mService.setPermittedInputMethods(admin, packageNames);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -4446,7 +4497,7 @@
try {
return mService.getPermittedInputMethods(admin);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -4468,7 +4519,7 @@
try {
return mService.isInputMethodPermittedByAdmin(admin, packageName, userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -4491,7 +4542,7 @@
try {
return mService.getPermittedInputMethodsForCurrentUser();
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -4511,7 +4562,7 @@
try {
return mService.getKeepUninstalledPackages(admin);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -4534,7 +4585,7 @@
try {
mService.setKeepUninstalledPackages(admin, packageNames);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -4639,9 +4690,8 @@
try {
return mService.createAndManageUser(admin, name, profileOwner, adminExtras, flags);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -4656,8 +4706,7 @@
try {
return mService.removeUser(admin, userHandle);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -4674,8 +4723,7 @@
try {
return mService.switchUser(admin, userHandle);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -4701,7 +4749,7 @@
try {
return mService.getApplicationRestrictions(admin, packageName);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -4723,7 +4771,7 @@
try {
mService.setUserRestriction(admin, key, true);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -4744,7 +4792,7 @@
try {
mService.setUserRestriction(admin, key, false);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -4771,7 +4819,7 @@
try {
ret = mService.getUserRestrictions(admin, userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return ret == null ? new Bundle() : ret;
@@ -4793,7 +4841,7 @@
try {
return mService.setApplicationHidden(admin, packageName, hidden);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -4811,7 +4859,7 @@
try {
return mService.isApplicationHidden(admin, packageName);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -4829,7 +4877,7 @@
try {
mService.enableSystemApp(admin, packageName);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -4848,7 +4896,7 @@
try {
return mService.enableSystemAppWithIntent(admin, intent);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return 0;
@@ -4879,7 +4927,7 @@
try {
mService.setAccountManagementDisabled(admin, accountType, disabled);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -4907,7 +4955,7 @@
try {
return mService.getAccountTypesWithManagementDisabledAsUser(userId);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -4938,7 +4986,7 @@
try {
mService.setLockTaskPackages(admin, packages);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -4954,7 +5002,7 @@
try {
return mService.getLockTaskPackages(admin);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -4970,7 +5018,7 @@
try {
return mService.isLockTaskPermitted(pkg);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return false;
@@ -5017,7 +5065,7 @@
try {
mService.setGlobalSetting(admin, setting, value);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -5045,7 +5093,7 @@
try {
mService.setSecureSetting(admin, setting, value);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -5066,7 +5114,7 @@
try {
mService.setRestrictionsProvider(admin, provider);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
}
@@ -5082,7 +5130,7 @@
try {
mService.setMasterVolumeMuted(admin, on);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
}
@@ -5098,7 +5146,7 @@
try {
return mService.isMasterVolumeMuted(admin);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
return false;
@@ -5118,7 +5166,7 @@
try {
mService.setUninstallBlocked(admin, packageName, uninstallBlocked);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
}
@@ -5142,7 +5190,7 @@
try {
return mService.isUninstallBlocked(admin, packageName);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
return false;
@@ -5170,7 +5218,7 @@
try {
return mService.addCrossProfileWidgetProvider(admin, packageName);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
return false;
@@ -5198,7 +5246,7 @@
try {
return mService.removeCrossProfileWidgetProvider(admin, packageName);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
return false;
@@ -5222,7 +5270,7 @@
return providers;
}
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
return Collections.emptyList();
@@ -5238,7 +5286,7 @@
try {
mService.setUserIcon(admin, icon);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -5258,7 +5306,7 @@
try {
mService.setSystemUpdatePolicy(admin, policy);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
}
@@ -5273,7 +5321,7 @@
try {
return mService.getSystemUpdatePolicy();
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
return null;
@@ -5297,8 +5345,7 @@
try {
return mService.setKeyguardDisabled(admin, disabled);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -5317,8 +5364,7 @@
try {
return mService.setStatusBarDisabled(admin, disabled);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -5337,7 +5383,7 @@
try {
mService.notifyPendingSystemUpdate(updateReceivedTime);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
}
@@ -5363,7 +5409,7 @@
try {
mService.setPermissionPolicy(admin, policy);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -5377,7 +5423,7 @@
try {
return mService.getPermissionPolicy(admin);
} catch (RemoteException re) {
- return PERMISSION_POLICY_PROMPT;
+ throw re.rethrowFromSystemServer();
}
}
@@ -5414,8 +5460,7 @@
try {
return mService.setPermissionGrantState(admin, packageName, permission, grantState);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -5441,8 +5486,7 @@
try {
return mService.getPermissionGrantState(admin, packageName, permission);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- return PERMISSION_GRANT_STATE_DEFAULT;
+ throw re.rethrowFromSystemServer();
}
}
@@ -5460,8 +5504,7 @@
try {
return mService.isProvisioningAllowed(action);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -5477,8 +5520,7 @@
try {
return mService.isManagedProfile(admin);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -5493,8 +5535,7 @@
try {
return mService.isSystemOnlyUser(admin);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -5510,8 +5551,7 @@
try {
return mService.getWifiMacAddress();
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -5522,7 +5562,7 @@
try {
mService.reboot(admin);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -5552,7 +5592,7 @@
try {
mService.setShortSupportMessage(admin, message);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -5569,7 +5609,7 @@
try {
return mService.getShortSupportMessage(admin);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -5595,7 +5635,7 @@
try {
mService.setLongSupportMessage(admin, message);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -5612,7 +5652,7 @@
try {
return mService.getLongSupportMessage(admin);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -5632,7 +5672,7 @@
try {
return mService.getShortSupportMessageForUser(admin, userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -5653,7 +5693,7 @@
try {
return mService.getLongSupportMessageForUser(admin, userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -5674,8 +5714,7 @@
}
return new DevicePolicyManager(mContext, true);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -5697,7 +5736,7 @@
try {
mService.setDeviceLoggingEnabled(admin, enabled);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -5714,8 +5753,7 @@
try {
return mService.getDeviceLoggingEnabled(admin);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -5743,8 +5781,7 @@
return null;
}
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -5784,8 +5821,7 @@
ParceledListSlice<SecurityEvent> list = mService.retrievePreviousDeviceLogs(admin);
return list.getList();
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- return Collections.<SecurityEvent>emptyList();
+ throw re.rethrowFromSystemServer();
}
}
@@ -5804,7 +5840,7 @@
try {
mService.setOrganizationColor(admin, color);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -5823,7 +5859,7 @@
try {
mService.setOrganizationColorForUser(color, userId);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -5838,8 +5874,7 @@
try {
return mService.getOrganizationColor(admin);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- return 0;
+ throw re.rethrowFromSystemServer();
}
}
@@ -5854,8 +5889,7 @@
try {
return mService.getOrganizationColorForUser(userHandle);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- return 0;
+ throw re.rethrowFromSystemServer();
}
}
@@ -5874,7 +5908,7 @@
try {
mService.setOrganizationName(admin, title);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+ throw re.rethrowFromSystemServer();
}
}
@@ -5889,8 +5923,7 @@
try {
return mService.getOrganizationName(admin);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -5906,8 +5939,7 @@
try {
return mService.getOrganizationNameForUser(userHandle);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -5923,7 +5955,7 @@
try {
return mService.getUserProvisioningState();
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
return STATE_USER_UNMANAGED;
@@ -5941,7 +5973,7 @@
try {
mService.setUserProvisioningState(state, userHandle);
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -5968,7 +6000,7 @@
try {
mService.setAffiliationIds(admin, new ArrayList<String>(ids));
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -5983,8 +6015,7 @@
try {
return mService != null && mService.isAffiliatedUser();
} catch (RemoteException e) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -5999,8 +6030,7 @@
try {
return mService.isUninstallInQueue(packageName);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -6012,7 +6042,7 @@
try {
mService.uninstallPackageWithActiveAdmins(packageName);
} catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ throw re.rethrowFromSystemServer();
}
}
}
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/bluetooth/OobData.java b/core/java/android/bluetooth/OobData.java
index 7194938..70d47ee 100644
--- a/core/java/android/bluetooth/OobData.java
+++ b/core/java/android/bluetooth/OobData.java
@@ -25,7 +25,7 @@
* Out Of Band Data for Bluetooth device.
* @hide
*/
-public final class OobData implements Parcelable {
+public class OobData implements Parcelable {
private byte[] securityManagerTk;
public byte[] getSecurityManagerTk() {
diff --git a/core/java/android/content/pm/AppsQueryHelper.java b/core/java/android/content/pm/AppsQueryHelper.java
index e542589..4c01b27 100644
--- a/core/java/android/content/pm/AppsQueryHelper.java
+++ b/core/java/android/content/pm/AppsQueryHelper.java
@@ -171,7 +171,7 @@
return mPackageManager.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES
| PackageManager.GET_DISABLED_COMPONENTS, userId).getList();
} catch (RemoteException e) {
- throw new IllegalStateException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -181,9 +181,9 @@
return mPackageManager.queryIntentActivities(intent, null,
PackageManager.GET_DISABLED_COMPONENTS
| PackageManager.GET_UNINSTALLED_PACKAGES,
- userId);
+ userId).getList();
} catch (RemoteException e) {
- throw new IllegalStateException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -192,9 +192,9 @@
try {
return mPackageManager.queryIntentServices(intent, null,
PackageManager.GET_META_DATA
- | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId);
+ | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId).getList();
} catch (RemoteException e) {
- throw new IllegalStateException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -205,8 +205,7 @@
return mPackageManager.getPackagesHoldingPermissions(new String[]{perm}, 0,
userId).getList();
} catch (RemoteException e) {
- throw new IllegalStateException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
-
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 9959f27..c684447 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -71,11 +71,11 @@
PermissionInfo getPermissionInfo(String name, int flags);
- List<PermissionInfo> queryPermissionsByGroup(String group, int flags);
+ ParceledListSlice queryPermissionsByGroup(String group, int flags);
PermissionGroupInfo getPermissionGroupInfo(String name, int flags);
- List<PermissionGroupInfo> getAllPermissionGroups(int flags);
+ ParceledListSlice getAllPermissionGroups(int flags);
ApplicationInfo getApplicationInfo(String packageName, int flags ,int userId);
@@ -120,6 +120,8 @@
int checkUidSignatures(int uid1, int uid2);
+ List<String> getAllPackages();
+
String[] getPackagesForUid(int uid);
String getNameForUid(int uid);
@@ -138,24 +140,24 @@
boolean canForwardTo(in Intent intent, String resolvedType, int sourceUserId, int targetUserId);
- List<ResolveInfo> queryIntentActivities(in Intent intent,
+ ParceledListSlice queryIntentActivities(in Intent intent,
String resolvedType, int flags, int userId);
- List<ResolveInfo> queryIntentActivityOptions(
+ ParceledListSlice queryIntentActivityOptions(
in ComponentName caller, in Intent[] specifics,
in String[] specificTypes, in Intent intent,
String resolvedType, int flags, int userId);
- List<ResolveInfo> queryIntentReceivers(in Intent intent,
+ ParceledListSlice queryIntentReceivers(in Intent intent,
String resolvedType, int flags, int userId);
ResolveInfo resolveService(in Intent intent,
String resolvedType, int flags, int userId);
- List<ResolveInfo> queryIntentServices(in Intent intent,
+ ParceledListSlice queryIntentServices(in Intent intent,
String resolvedType, int flags, int userId);
- List<ResolveInfo> queryIntentContentProviders(in Intent intent,
+ ParceledListSlice queryIntentContentProviders(in Intent intent,
String resolvedType, int flags, int userId);
/**
@@ -189,7 +191,7 @@
* @return A List<applicationInfo> containing one entry for each persistent
* application.
*/
- List<ApplicationInfo> getPersistentApplications(int flags);
+ ParceledListSlice getPersistentApplications(int flags);
ProviderInfo resolveContentProvider(String name, int flags, int userId);
@@ -210,7 +212,7 @@
InstrumentationInfo getInstrumentationInfo(
in ComponentName className, int flags);
- List<InstrumentationInfo> queryInstrumentation(
+ ParceledListSlice queryInstrumentation(
String targetPackage, int flags);
/** @deprecated Use PackageInstaller instead */
@@ -240,12 +242,6 @@
String getInstallerPackageName(in String packageName);
- void addPackageToPreferred(String packageName);
-
- void removePackageFromPreferred(String packageName);
-
- List<PackageInfo> getPreferredPackages(int flags);
-
void resetApplicationPreferences(int userId);
ResolveInfo getLastChosenActivity(in Intent intent,
@@ -386,6 +382,13 @@
*/
void clearApplicationUserData(in String packageName, IPackageDataObserver observer, int userId);
+ /**
+ * Clear the profile data of an application.
+ * @param packageName The package name of the application whose profile data
+ * need to be deleted
+ */
+ void clearApplicationProfileData(in String packageName);
+
/**
* Get package statistics including the code, data and cache size for
* an already installed package
@@ -406,7 +409,7 @@
* Get a list of features that are available on the
* system.
*/
- FeatureInfo[] getSystemAvailableFeatures();
+ ParceledListSlice getSystemAvailableFeatures();
boolean hasSystemFeature(String name, int version);
@@ -480,8 +483,8 @@
void verifyIntentFilter(int id, int verificationCode, in List<String> failedDomains);
int getIntentVerificationStatus(String packageName, int userId);
boolean updateIntentVerificationStatus(String packageName, int status, int userId);
- List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName);
- List<IntentFilter> getAllIntentFilters(String packageName);
+ ParceledListSlice getIntentFilterVerifications(String packageName);
+ ParceledListSlice getAllIntentFilters(String packageName);
boolean setDefaultBrowserPackageName(String packageName, int userId);
String getDefaultBrowserPackageName(int userId);
@@ -530,4 +533,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/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 4df83036..edd888b 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -16,12 +16,16 @@
package android.content.pm;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcel;
import android.os.UserHandle;
+import android.text.BidiFormatter;
+import android.text.TextPaint;
import android.text.TextUtils;
import android.util.Printer;
@@ -38,6 +42,8 @@
* in the implementation of Parcelable in subclasses.
*/
public class PackageItemInfo {
+ private static final float MAX_LABEL_SIZE_PX = 500f;
+
/**
* Public name of this item. From the "android:name" attribute.
*/
@@ -140,6 +146,56 @@
}
/**
+ * Same as {@link #loadLabel(PackageManager)} with the addition that
+ * the returned label is safe for being presented in the UI since it
+ * will not contain new lines and the length will be limited to a
+ * reasonable amount. This prevents a malicious party to influence UI
+ * layout via the app label misleading the user into performing a
+ * detrimental for them action. If the label is too long it will be
+ * truncated and ellipsized at the end.
+ *
+ * @param pm A PackageManager from which the label can be loaded; usually
+ * the PackageManager from which you originally retrieved this item
+ * @return Returns a CharSequence containing the item's label. If the
+ * item does not have a label, its name is returned.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm) {
+ // loadLabel() always returns non-null
+ CharSequence label = loadLabel(pm);
+
+ // If the label contains new line characters it may push the UI
+ // down to hide a part of it. Labels shouldn't have new line
+ // characters, so just truncate at the first time one is seen.
+ String labelStr = label.toString();
+ final int labelLength = labelStr.length();
+ int offset = 0;
+ while (offset < labelLength) {
+ final int codePoint = labelStr.codePointAt(offset);
+ final int type = Character.getType(codePoint);
+ if (type == Character.LINE_SEPARATOR
+ || type == Character.CONTROL
+ || type == Character.PARAGRAPH_SEPARATOR) {
+ labelStr = labelStr.substring(0, offset);
+ break;
+ }
+ offset += Character.charCount(codePoint);
+ }
+
+ if (labelStr.isEmpty()) {
+ return labelStr;
+ }
+
+ TextPaint paint = new TextPaint();
+ paint.setTextSize(42);
+
+ return TextUtils.ellipsize(labelStr, paint, MAX_LABEL_SIZE_PX,
+ TextUtils.TruncateAt.END);
+ }
+
+ /**
* Retrieve the current graphical icon associated with this item. This
* will call back on the given PackageManager to load the icon from
* the application.
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/ConsumerIrManager.java b/core/java/android/hardware/ConsumerIrManager.java
index 6d29212..9fa1c3f 100644
--- a/core/java/android/hardware/ConsumerIrManager.java
+++ b/core/java/android/hardware/ConsumerIrManager.java
@@ -60,8 +60,8 @@
try {
return mService.hasIrEmitter();
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return false;
}
/**
@@ -84,7 +84,7 @@
try {
mService.transmit(mPackageName, carrierFrequency, pattern);
} catch (RemoteException e) {
- Log.w(TAG, "failed to transmit.", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -149,8 +149,7 @@
}
return range;
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return null;
}
-
}
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/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/SensorEventListener.java b/core/java/android/hardware/SensorEventListener.java
index 0d859fb9..0c059ba 100644
--- a/core/java/android/hardware/SensorEventListener.java
+++ b/core/java/android/hardware/SensorEventListener.java
@@ -18,28 +18,33 @@
/**
* Used for receiving notifications from the SensorManager when
- * sensor values have changed.
+ * there is new sensor data.
*/
public interface SensorEventListener {
/**
- * Called when sensor values have changed.
+ * Called when there is a new sensor event. Note that "on changed"
+ * is somewhat of a misnomer, as this will also be called if we have a
+ * new reading from a sensor with the exact same sensor values (but a
+ * newer timestamp).
+ *
* <p>See {@link android.hardware.SensorManager SensorManager}
* for details on possible sensor types.
* <p>See also {@link android.hardware.SensorEvent SensorEvent}.
- *
+ *
* <p><b>NOTE:</b> The application doesn't own the
* {@link android.hardware.SensorEvent event}
* object passed as a parameter and therefore cannot hold on to it.
* The object may be part of an internal pool and may be reused by
* the framework.
*
- * @param event the {@link android.hardware.SensorEvent SensorEvent}.
+ * @param event the {@link android.hardware.SensorEvent SensorEvent}.
*/
public void onSensorChanged(SensorEvent event);
/**
- * Called when the accuracy of the registered sensor has changed.
+ * Called when the accuracy of the registered sensor has changed. Unlike
+ * onSensorChanged(), this is only called when this accuracy value changes.
*
* <p>See the SENSOR_STATUS_* constants in
* {@link android.hardware.SensorManager SensorManager} for details.
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index f0b17c30..5684aa5 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -46,7 +46,7 @@
* is an example of a trigger sensor.
* </p>
* <pre class="prettyprint">
- * public class SensorActivity extends Activity, implements SensorEventListener {
+ * public class SensorActivity extends Activity implements SensorEventListener {
* private final SensorManager mSensorManager;
* private final Sensor mAccelerometer;
*
diff --git a/core/java/android/hardware/SerialManager.java b/core/java/android/hardware/SerialManager.java
index e0680bf22..83f7649 100644
--- a/core/java/android/hardware/SerialManager.java
+++ b/core/java/android/hardware/SerialManager.java
@@ -14,13 +14,11 @@
* limitations under the License.
*/
-
package android.hardware;
import android.content.Context;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
-import android.util.Log;
import java.io.IOException;
@@ -50,8 +48,7 @@
try {
return mService.getSerialPorts();
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in getSerialPorts", e);
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -77,8 +74,7 @@
throw new IOException("Could not open serial port " + name);
}
} catch (RemoteException e) {
- Log.e(TAG, "exception in UsbManager.openDevice", e);
+ throw e.rethrowFromSystemServer();
}
- return null;
}
}
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/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index abd02f0..b8088f3 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -540,7 +540,7 @@
if (mService != null) try {
result = mService.preEnroll(mToken);
} catch (RemoteException e) {
- Log.w(TAG, "Remote exception in enroll: ", e);
+ throw e.rethrowFromSystemServer();
}
return result;
}
@@ -555,7 +555,7 @@
if (mService != null) try {
result = mService.postEnroll(mToken);
} catch (RemoteException e) {
- Log.w(TAG, "Remote exception in post enroll: ", e);
+ throw e.rethrowFromSystemServer();
}
return result;
}
@@ -571,7 +571,7 @@
if (mService != null) try {
mService.setActiveUser(userId);
} catch (RemoteException e) {
- Log.w(TAG, "Remote exception in setActiveUser: ", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -614,7 +614,7 @@
try {
mService.rename(fpId, userId, newName);
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in rename(): ", e);
+ throw e.rethrowFromSystemServer();
}
} else {
Log.w(TAG, "rename(): Service not connected!");
@@ -632,7 +632,7 @@
if (mService != null) try {
return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
+ throw e.rethrowFromSystemServer();
}
return null;
}
@@ -659,7 +659,7 @@
return mService.hasEnrolledFingerprints(
UserHandle.myUserId(), mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
+ throw e.rethrowFromSystemServer();
}
return false;
}
@@ -674,7 +674,7 @@
if (mService != null) try {
return mService.hasEnrolledFingerprints(userId, mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
+ throw e.rethrowFromSystemServer();
}
return false;
}
@@ -691,7 +691,7 @@
long deviceId = 0; /* TODO: plumb hardware id to FPMS */
return mService.isHardwareDetected(deviceId, mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e);
+ throw e.rethrowFromSystemServer();
}
} else {
Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
@@ -710,7 +710,7 @@
try {
return mService.getAuthenticatorId(mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in getAuthenticatorId(): ", e);
+ throw e.rethrowFromSystemServer();
}
} else {
Log.w(TAG, "getAuthenticatorId(): Service not connected!");
@@ -730,7 +730,7 @@
try {
mService.resetTimeout(token);
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in resetTimeout(): ", e);
+ throw e.rethrowFromSystemServer();
}
} else {
Log.w(TAG, "resetTimeout(): Service not connected!");
@@ -765,7 +765,7 @@
}
});
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in addLockoutResetCallback(): ", e);
+ throw e.rethrowFromSystemServer();
}
} else {
Log.w(TAG, "addLockoutResetCallback(): Service not connected!");
@@ -881,8 +881,7 @@
try {
return ActivityManagerNative.getDefault().getCurrentUser().id;
} catch (RemoteException e) {
- Log.w(TAG, "Failed to get current user id\n");
- return UserHandle.USER_NULL;
+ throw e.rethrowFromSystemServer();
}
}
@@ -890,7 +889,7 @@
if (mService != null) try {
mService.cancelEnrollment(mToken);
} catch (RemoteException e) {
- if (DEBUG) Log.w(TAG, "Remote exception while canceling enrollment");
+ throw e.rethrowFromSystemServer();
}
}
@@ -898,7 +897,7 @@
if (mService != null) try {
mService.cancelAuthentication(mToken, mContext.getOpPackageName());
} catch (RemoteException e) {
- if (DEBUG) Log.w(TAG, "Remote exception while canceling enrollment");
+ throw e.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 6effc0d..ff87b67 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -267,7 +267,7 @@
try {
types = mService.getSupportedTypes();
} catch (RemoteException e) {
- // Do nothing.
+ throw e.rethrowFromSystemServer();
}
}
mHasTvDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_TV);
@@ -403,7 +403,7 @@
try {
mService.addHotplugEventListener(wrappedListener);
} catch (RemoteException e) {
- Log.e(TAG, "failed to add hotplug event listener: ", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -425,7 +425,7 @@
try {
mService.removeHotplugEventListener(wrappedListener);
} catch (RemoteException e) {
- Log.e(TAG, "failed to remove hotplug event listener: ", e);
+ throw e.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index cbe3412..fbac58c 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -252,7 +252,7 @@
try {
inputDevice = mIm.getInputDevice(id);
} catch (RemoteException ex) {
- throw new RuntimeException("Could not get input device information.", ex);
+ throw ex.rethrowFromSystemServer();
}
if (inputDevice != null) {
mInputDevices.setValueAt(index, inputDevice);
@@ -284,7 +284,7 @@
try {
inputDevice = mIm.getInputDevice(id);
} catch (RemoteException ex) {
- // Ignore the problem for the purposes of this method.
+ throw ex.rethrowFromSystemServer();
}
if (inputDevice == null) {
continue;
@@ -384,8 +384,7 @@
try {
return mIm.isInTabletMode();
} catch (RemoteException ex) {
- Log.w(TAG, "Could not get tablet mode state", ex);
- return SWITCH_STATE_UNKNOWN;
+ throw ex.rethrowFromSystemServer();
}
}
@@ -439,7 +438,7 @@
try {
mIm.registerTabletModeChangedListener(listener);
} catch (RemoteException ex) {
- throw new RuntimeException("Could not register tablet mode changed listener", ex);
+ throw ex.rethrowFromSystemServer();
}
mTabletModeChangedListener = listener;
mOnTabletModeChangedListeners = new ArrayList<>();
@@ -471,8 +470,7 @@
try {
return mIm.getKeyboardLayouts();
} catch (RemoteException ex) {
- Log.w(TAG, "Could not get list of keyboard layout informations.", ex);
- return new KeyboardLayout[0];
+ throw ex.rethrowFromSystemServer();
}
}
@@ -494,8 +492,7 @@
try {
return mIm.getKeyboardLayoutsForInputDevice(identifier);
} catch (RemoteException ex) {
- Log.w(TAG, "Could not get list of keyboard layouts for input device.", ex);
- return new KeyboardLayout[0];
+ throw ex.rethrowFromSystemServer();
}
}
@@ -516,8 +513,7 @@
try {
return mIm.getKeyboardLayout(keyboardLayoutDescriptor);
} catch (RemoteException ex) {
- Log.w(TAG, "Could not get keyboard layout information.", ex);
- return null;
+ throw ex.rethrowFromSystemServer();
}
}
@@ -534,8 +530,7 @@
try {
return mIm.getCurrentKeyboardLayoutForInputDevice(identifier);
} catch (RemoteException ex) {
- Log.w(TAG, "Could not get current keyboard layout for input device.", ex);
- return null;
+ throw ex.rethrowFromSystemServer();
}
}
@@ -565,7 +560,7 @@
mIm.setCurrentKeyboardLayoutForInputDevice(identifier,
keyboardLayoutDescriptor);
} catch (RemoteException ex) {
- Log.w(TAG, "Could not set current keyboard layout for input device.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -585,8 +580,7 @@
try {
return mIm.getEnabledKeyboardLayoutsForInputDevice(identifier);
} catch (RemoteException ex) {
- Log.w(TAG, "Could not get keyboard layouts for input device.", ex);
- return ArrayUtils.emptyArray(String.class);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -614,7 +608,7 @@
try {
mIm.addKeyboardLayoutForInputDevice(identifier, keyboardLayoutDescriptor);
} catch (RemoteException ex) {
- Log.w(TAG, "Could not add keyboard layout for input device.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -642,7 +636,7 @@
try {
mIm.removeKeyboardLayoutForInputDevice(identifier, keyboardLayoutDescriptor);
} catch (RemoteException ex) {
- Log.w(TAG, "Could not remove keyboard layout for input device.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -664,8 +658,7 @@
return mIm.getKeyboardLayoutForInputDevice(
identifier, inputMethodInfo, inputMethodSubtype);
} catch (RemoteException ex) {
- Log.w(TAG, "Could not set keyboard layout.", ex);
- return null;
+ throw ex.rethrowFromSystemServer();
}
}
@@ -687,7 +680,7 @@
mIm.setKeyboardLayoutForInputDevice(identifier, inputMethodInfo,
inputMethodSubtype, keyboardLayoutDescriptor);
} catch (RemoteException ex) {
- Log.w(TAG, "Could not set keyboard layout.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -704,8 +697,7 @@
try {
return mIm.getTouchCalibrationForInputDevice(inputDeviceDescriptor, surfaceRotation);
} catch (RemoteException ex) {
- Log.w(TAG, "Could not get calibration matrix for input device.", ex);
- return TouchCalibration.IDENTITY;
+ throw ex.rethrowFromSystemServer();
}
}
@@ -726,7 +718,7 @@
try {
mIm.setTouchCalibrationForInputDevice(inputDeviceDescriptor, surfaceRotation, calibration);
} catch (RemoteException ex) {
- Log.w(TAG, "Could not set calibration matrix for input device.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -793,7 +785,7 @@
try {
mIm.tryPointerSpeed(speed);
} catch (RemoteException ex) {
- Log.w(TAG, "Could not set temporary pointer speed.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -831,7 +823,7 @@
try {
mIm.hasKeys(id, InputDevice.SOURCE_ANY, keyCodes, ret);
} catch (RemoteException e) {
- // no fallback; just return the empty array
+ throw e.rethrowFromSystemServer();
}
return ret;
}
@@ -871,7 +863,7 @@
try {
return mIm.injectInputEvent(event, mode);
} catch (RemoteException ex) {
- return false;
+ throw ex.rethrowFromSystemServer();
}
}
@@ -887,7 +879,7 @@
try {
mIm.setPointerIconShape(iconId);
} catch (RemoteException ex) {
- // Do nothing.
+ throw ex.rethrowFromSystemServer();
}
}
@@ -896,7 +888,7 @@
try {
mIm.setCustomPointerIcon(icon);
} catch (RemoteException ex) {
- // Do nothing.
+ throw ex.rethrowFromSystemServer();
}
}
@@ -914,7 +906,7 @@
try {
mIm.setPointerIconDetached(detached);
} catch (RemoteException ex) {
- // Do nothing.
+ throw ex.rethrowFromSystemServer();
}
}
@@ -924,8 +916,7 @@
try {
mIm.registerInputDevicesChangedListener(listener);
} catch (RemoteException ex) {
- throw new RuntimeException(
- "Could not get register input device changed listener", ex);
+ throw ex.rethrowFromSystemServer();
}
mInputDevicesChangedListener = listener;
}
@@ -935,7 +926,7 @@
try {
ids = mIm.getInputDeviceIds();
} catch (RemoteException ex) {
- throw new RuntimeException("Could not get input device ids.", ex);
+ throw ex.rethrowFromSystemServer();
}
mInputDevices = new SparseArray<InputDevice>();
@@ -1175,7 +1166,7 @@
try {
mIm.vibrate(mDeviceId, pattern, repeat, mToken);
} catch (RemoteException ex) {
- Log.w(TAG, "Failed to vibrate.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -1184,7 +1175,7 @@
try {
mIm.cancelVibrate(mDeviceId, mToken);
} catch (RemoteException ex) {
- Log.w(TAG, "Failed to cancel vibration.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
}
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/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 7004e97..5f1043b 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -45,10 +45,12 @@
import android.telephony.SubscriptionManager;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.SparseArray;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.util.Protocol;
+import com.android.internal.util.MessageUtils;
import libcore.net.event.NetworkEventDispatcher;
@@ -79,6 +81,13 @@
public class ConnectivityManager {
private static final String TAG = "ConnectivityManager";
+ private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
+ new Class[]{ConnectivityManager.class}, new String[]{"CALLBACK_"});
+
+ private static final String whatToString(int what) {
+ return sMagicDecoderRing.get(what, Integer.toString(what));
+ }
+
/**
* A change in network connectivity has occurred. A default connection has either
* been established or lost. The NetworkInfo for the affected network is
@@ -733,7 +742,7 @@
try {
return mService.getActiveNetworkInfo();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -753,7 +762,7 @@
try {
return mService.getActiveNetwork();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -777,7 +786,7 @@
try {
return mService.setAlwaysOnVpnPackage(userId, vpnPackage);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -794,7 +803,7 @@
try {
return mService.getAlwaysOnVpnPackage(userId);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -815,7 +824,7 @@
try {
return mService.getActiveNetworkInfoForUid(uid);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -839,7 +848,7 @@
try {
return mService.getNetworkInfo(networkType);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -859,7 +868,7 @@
try {
return mService.getNetworkInfoForNetwork(network);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -880,7 +889,7 @@
try {
return mService.getAllNetworkInfo();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -900,7 +909,7 @@
try {
return mService.getNetworkForType(networkType);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -916,7 +925,7 @@
try {
return mService.getAllNetworks();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -929,7 +938,7 @@
try {
return mService.getDefaultNetworkCapabilitiesForUser(userId);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -948,7 +957,7 @@
try {
return mService.getActiveLinkProperties();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -972,7 +981,7 @@
try {
return mService.getLinkPropertiesForType(networkType);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -989,7 +998,7 @@
try {
return mService.getLinkProperties(network);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1006,7 +1015,7 @@
try {
return mService.getNetworkCapabilities(network);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1024,7 +1033,7 @@
try {
return mService.getCaptivePortalServerUrl();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1324,7 +1333,9 @@
int type = legacyTypeForNetworkCapabilities(netCap);
try {
delay = mService.getRestoreDefaultNetworkDelay(type);
- } catch (RemoteException e) {}
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
LegacyRequest l = new LegacyRequest();
l.networkCapabilities = netCap;
l.delay = delay;
@@ -1542,7 +1553,7 @@
try {
return mService.requestRouteToHostAddress(networkType, hostAddress.getAddress());
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1598,7 +1609,7 @@
try {
return mService.getActiveNetworkQuotaInfo();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1617,7 +1628,9 @@
Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId
+ " retVal=" + retVal);
return retVal;
- } catch (RemoteException e) { }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
Log.d("ConnectivityManager", "getMobileDataEnabled()- remote exception retVal=false");
return false;
@@ -1678,6 +1691,7 @@
getNetworkManagementService().registerNetworkActivityListener(rl);
mNetworkActivityListeners.put(l, rl);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1695,6 +1709,7 @@
try {
getNetworkManagementService().unregisterNetworkActivityListener(rl);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1710,8 +1725,8 @@
try {
return getNetworkManagementService().isNetworkActive();
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return false;
}
/**
@@ -1785,7 +1800,7 @@
try {
return mService.getTetherableIfaces();
} catch (RemoteException e) {
- return new String[0];
+ throw e.rethrowFromSystemServer();
}
}
@@ -1802,7 +1817,7 @@
try {
return mService.getTetheredIfaces();
} catch (RemoteException e) {
- return new String[0];
+ throw e.rethrowFromSystemServer();
}
}
@@ -1825,7 +1840,7 @@
try {
return mService.getTetheringErroredIfaces();
} catch (RemoteException e) {
- return new String[0];
+ throw e.rethrowFromSystemServer();
}
}
@@ -1839,7 +1854,7 @@
try {
return mService.getTetheredDhcpRanges();
} catch (RemoteException e) {
- return new String[0];
+ throw e.rethrowFromSystemServer();
}
}
@@ -1871,7 +1886,7 @@
try {
return mService.tether(iface);
} catch (RemoteException e) {
- return TETHER_ERROR_SERVICE_UNAVAIL;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1897,7 +1912,7 @@
try {
return mService.untether(iface);
} catch (RemoteException e) {
- return TETHER_ERROR_SERVICE_UNAVAIL;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1917,7 +1932,7 @@
try {
return mService.isTetheringSupported();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2005,7 +2020,7 @@
try {
mService.stopTethering(type);
} catch (RemoteException e) {
- Log.e(TAG, "Exception trying to stop tethering.", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2025,7 +2040,7 @@
try {
return mService.getTetherableUsbRegexs();
} catch (RemoteException e) {
- return new String[0];
+ throw e.rethrowFromSystemServer();
}
}
@@ -2045,7 +2060,7 @@
try {
return mService.getTetherableWifiRegexs();
} catch (RemoteException e) {
- return new String[0];
+ throw e.rethrowFromSystemServer();
}
}
@@ -2065,7 +2080,7 @@
try {
return mService.getTetherableBluetoothRegexs();
} catch (RemoteException e) {
- return new String[0];
+ throw e.rethrowFromSystemServer();
}
}
@@ -2090,7 +2105,7 @@
try {
return mService.setUsbTethering(enable);
} catch (RemoteException e) {
- return TETHER_ERROR_SERVICE_UNAVAIL;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2135,7 +2150,7 @@
try {
return mService.getLastTetherError(iface);
} catch (RemoteException e) {
- return TETHER_ERROR_SERVICE_UNAVAIL;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2153,6 +2168,7 @@
try {
mService.reportInetCondition(networkType, percentage);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2174,6 +2190,7 @@
mService.reportNetworkConnectivity(network, true);
mService.reportNetworkConnectivity(network, false);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2192,6 +2209,7 @@
try {
mService.reportNetworkConnectivity(network, hasConnectivity);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2211,6 +2229,7 @@
try {
mService.setGlobalProxy(p);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2225,7 +2244,7 @@
try {
return mService.getGlobalProxy();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2247,7 +2266,7 @@
try {
return mService.getProxyForNetwork(network);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2282,8 +2301,9 @@
public boolean isNetworkSupported(int networkType) {
try {
return mService.isNetworkSupported(networkType);
- } catch (RemoteException e) {}
- return false;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -2303,7 +2323,7 @@
try {
return mService.isActiveNetworkMetered();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2320,7 +2340,7 @@
try {
return mService.updateLockdownVpn();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2339,6 +2359,7 @@
try {
timeOutMs = mService.checkMobileProvisioning(suggestedTimeOutMs);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
return timeOutMs;
}
@@ -2351,8 +2372,8 @@
try {
return mService.getMobileProvisioningUrl();
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -2369,6 +2390,7 @@
try {
mService.setProvisioningNotificationVisible(visible, networkType, action);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2385,6 +2407,7 @@
try {
mService.setAirplaneMode(enable);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2392,14 +2415,18 @@
public void registerNetworkFactory(Messenger messenger, String name) {
try {
mService.registerNetworkFactory(messenger, name);
- } catch (RemoteException e) { }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/** {@hide} */
public void unregisterNetworkFactory(Messenger messenger) {
try {
mService.unregisterNetworkFactory(messenger);
- } catch (RemoteException e) { }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -2412,7 +2439,7 @@
try {
return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc);
} catch (RemoteException e) {
- return NETID_UNSET;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2563,9 +2590,11 @@
@Override
public void handleMessage(Message message) {
- if (DBG) Log.d(TAG, "CM callback handler got msg " + message.what);
NetworkRequest request = (NetworkRequest) getObject(message, NetworkRequest.class);
Network network = (Network) getObject(message, Network.class);
+ if (DBG) {
+ Log.d(TAG, whatToString(message.what) + " for network " + network);
+ }
switch (message.what) {
case CALLBACK_PRECHECK: {
NetworkCallback callback = getCallback(request, "PRECHECK");
@@ -2730,7 +2759,9 @@
sNetworkCallback.put(networkCallback.networkRequest, networkCallback);
}
}
- } catch (RemoteException e) {}
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
if (networkCallback.networkRequest == null) decCallbackHandlerRefCount();
return networkCallback.networkRequest;
}
@@ -2893,7 +2924,9 @@
checkPendingIntent(operation);
try {
mService.pendingRequestForNetwork(request.networkCapabilities, operation);
- } catch (RemoteException e) {}
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -2911,7 +2944,9 @@
checkPendingIntent(operation);
try {
mService.releasePendingNetworkRequest(operation);
- } catch (RemoteException e) {}
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
private void checkPendingIntent(PendingIntent intent) {
@@ -2970,7 +3005,9 @@
checkPendingIntent(operation);
try {
mService.pendingListenForNetwork(request.networkCapabilities, operation);
- } catch (RemoteException e) {}
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -2988,7 +3025,7 @@
try {
return mService.requestBandwidthUpdate(network);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -3008,7 +3045,9 @@
}
try {
mService.releaseNetworkRequest(networkCallback.networkRequest);
- } catch (RemoteException e) {}
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -3044,7 +3083,9 @@
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
try {
mService.setAcceptUnvalidated(network, accept, always);
- } catch (RemoteException e) {}
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -3055,6 +3096,7 @@
try {
mService.factoryReset();
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -3262,7 +3304,7 @@
try {
return getNetworkPolicyManager().getRestrictBackgroundByCaller();
} catch (RemoteException e) {
- return RESTRICT_BACKGROUND_STATUS_DISABLED;
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java
index f45737a..664b7b4 100644
--- a/core/java/android/net/EthernetManager.java
+++ b/core/java/android/net/EthernetManager.java
@@ -87,8 +87,8 @@
public IpConfiguration getConfiguration() {
try {
return mService.getConfiguration();
- } catch (NullPointerException | RemoteException e) {
- return new IpConfiguration();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -98,7 +98,8 @@
public void setConfiguration(IpConfiguration config) {
try {
mService.setConfiguration(config);
- } catch (NullPointerException | RemoteException e) {
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -109,8 +110,8 @@
public boolean isAvailable() {
try {
return mService.isAvailable();
- } catch (NullPointerException | RemoteException e) {
- return false;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -127,7 +128,8 @@
if (mListeners.size() == 1) {
try {
mService.addListener(mServiceListener);
- } catch (NullPointerException | RemoteException e) {
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -145,7 +147,8 @@
if (mListeners.isEmpty()) {
try {
mService.removeListener(mServiceListener);
- } catch (NullPointerException | RemoteException e) {
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
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/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index b6fe68a..01c160f 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -166,7 +166,7 @@
try {
return mService.updateScores(networks);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -186,7 +186,7 @@
try {
return mService.clearScores();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -206,7 +206,7 @@
try {
return mService.setActiveScorer(packageName);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -221,6 +221,7 @@
try {
mService.disableScoring();
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -265,6 +266,7 @@
try {
mService.registerNetworkScoreCache(networkType, scoreCache);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
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/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
index 377ed88..86bd502 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -619,7 +619,9 @@
public void setEnabled(boolean enabled) {
try {
mService.setEnabled(enabled);
- } catch (RemoteException e) { }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -632,7 +634,7 @@
try {
return mService.getMessenger();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 56cb250..e40ebf7 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -221,7 +221,7 @@
try {
return mBatteryStats.isCharging();
} catch (RemoteException e) {
- return true;
+ throw e.rethrowFromSystemServer();
}
}
@@ -246,7 +246,7 @@
else
ret = Long.MIN_VALUE;
} catch (RemoteException e) {
- ret = Long.MIN_VALUE;
+ throw e.rethrowFromSystemServer();
}
return ret;
diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java
index f48306a..9ca1dcd 100644
--- a/core/java/android/os/HardwarePropertiesManager.java
+++ b/core/java/android/os/HardwarePropertiesManager.java
@@ -79,8 +79,7 @@
try {
return mService.getDeviceTemperatures(mContext.getOpPackageName(), type);
} catch (RemoteException e) {
- Log.w(TAG, "Could not get device temperatures", e);
- return new float[0];
+ throw e.rethrowFromSystemServer();
}
default:
Log.w(TAG, "Unknown device temperature type.");
@@ -100,8 +99,7 @@
try {
return mService.getCpuUsages(mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.w(TAG, "Could not get CPU usages", e);
- return new CpuUsageInfo[0];
+ throw e.rethrowFromSystemServer();
}
}
@@ -117,8 +115,7 @@
try {
return mService.getFanSpeeds(mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.w(TAG, "Could not get fan speeds", e);
- return new float[0];
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 369ec15..2a4507c 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -620,6 +620,7 @@
try {
mService.userActivity(when, event, flags);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -671,6 +672,7 @@
try {
mService.goToSleep(time, reason, flags);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -697,6 +699,7 @@
try {
mService.wakeUp(time, "wakeUp", mContext.getOpPackageName());
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -707,6 +710,7 @@
try {
mService.wakeUp(time, reason, mContext.getOpPackageName());
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -735,6 +739,7 @@
try {
mService.nap(time);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -757,6 +762,7 @@
try {
mService.boostScreenBrightness(time);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -772,7 +778,7 @@
try {
return mService.isScreenBrightnessBoosted();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -790,6 +796,7 @@
try {
mService.setTemporaryScreenBrightnessSettingOverride(brightness);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -803,7 +810,7 @@
try {
return mService.isWakeLockLevelSupported(level);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -867,7 +874,7 @@
try {
return mService.isInteractive();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -884,6 +891,7 @@
try {
mService.reboot(false, reason, true);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -899,7 +907,7 @@
try {
return mService.isPowerSaveMode();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -916,7 +924,7 @@
try {
return mService.setPowerSaveMode(mode);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -936,7 +944,7 @@
try {
return mService.isDeviceIdleMode();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -956,7 +964,7 @@
try {
return mService.isLightDeviceIdleMode();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -975,7 +983,7 @@
try {
return mIDeviceIdleController.isPowerSaveWhitelistApp(packageName);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -992,6 +1000,7 @@
try {
mService.shutdown(confirm, reason, wait);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1118,6 +1127,7 @@
try {
mService.releaseWakeLock(mToken, 0);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1186,6 +1196,7 @@
mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
mHistoryTag);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
mHeld = true;
}
@@ -1224,6 +1235,7 @@
try {
mService.releaseWakeLock(mToken, flags);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
mHeld = false;
}
@@ -1280,6 +1292,7 @@
try {
mService.updateWakeLockWorkSource(mToken, mWorkSource, mHistoryTag);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
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/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 4b70649..ea0597d 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -438,10 +438,6 @@
final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setData(uri);
-
- // note that docsui treats this as *force* show advanced. So sending
- // false permits advanced to be shown based on user preferences.
- intent.putExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, isPrimary());
intent.putExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, true);
return intent;
}
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index 9a80e37..5eb8cc2 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -16,12 +16,14 @@
package android.print;
+import android.content.ComponentName;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.print.IPrinterDiscoveryObserver;
import android.print.IPrintDocumentAdapter;
import android.print.PrintJobId;
import android.print.IPrintJobStateChangeListener;
+import android.print.IPrintServicesChangeListener;
import android.print.PrinterId;
import android.print.PrintJobInfo;
import android.print.PrintAttributes;
@@ -45,8 +47,47 @@
void removePrintJobStateChangeListener(in IPrintJobStateChangeListener listener,
int userId);
- List<PrintServiceInfo> getInstalledPrintServices(int userId);
- List<PrintServiceInfo> getEnabledPrintServices(int userId);
+ /**
+ * Listen for changes to the installed and enabled print services.
+ *
+ * @param listener the listener to add
+ * @param userId the id of the user listening
+ *
+ * @see android.print.PrintManager#getPrintServices(int, String)
+ */
+ void addPrintServicesChangeListener(in IPrintServicesChangeListener listener,
+ int userId);
+
+ /**
+ * Stop listening for changes to the installed and enabled print services.
+ *
+ * @param listener the listener to remove
+ * @param userId the id of the user requesting the removal
+ *
+ * @see android.print.PrintManager#getPrintServices(int, String)
+ */
+ void removePrintServicesChangeListener(in IPrintServicesChangeListener listener,
+ int userId);
+
+ /**
+ * Get the print services.
+ *
+ * @param selectionFlags flags selecting which services to get
+ * @param selectedService if not null, the id of the print service to get
+ * @param userId the id of the user requesting the services
+ *
+ * @return the list of selected print services.
+ */
+ List<PrintServiceInfo> getPrintServices(int selectionFlags, int userId);
+
+ /**
+ * Enable or disable a print service.
+ *
+ * @param service The service to enabled or disable
+ * @param isEnabled whether the service should be enabled or disabled
+ * @param userId the id of the user requesting the services
+ */
+ void setPrintServiceEnabled(in ComponentName service, boolean isEnabled, int userId);
void createPrinterDiscoverySession(in IPrinterDiscoveryObserver observer, int userId);
void startPrinterDiscovery(in IPrinterDiscoveryObserver observer,
diff --git a/core/java/android/hardware/camera2/utils/LongParcelable.aidl b/core/java/android/print/IPrintServicesChangeListener.aidl
similarity index 70%
rename from core/java/android/hardware/camera2/utils/LongParcelable.aidl
rename to core/java/android/print/IPrintServicesChangeListener.aidl
index 98ad1b2..2a7ce89 100644
--- a/core/java/android/hardware/camera2/utils/LongParcelable.aidl
+++ b/core/java/android/print/IPrintServicesChangeListener.aidl
@@ -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 android.print;
-/** @hide */
-parcelable LongParcelable;
+/**
+ * Interface for observing print services changes.
+ *
+ * @hide
+ */
+oneway interface IPrintServicesChangeListener {
+ void onPrintServicesChanged();
+}
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 0540036..25fc968 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
+import android.content.ComponentName;
import android.content.Context;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
@@ -111,6 +112,38 @@
private static final boolean DEBUG = false;
private static final int MSG_NOTIFY_PRINT_JOB_STATE_CHANGED = 1;
+ private static final int MSG_NOTIFY_PRINT_SERVICES_CHANGED = 2;
+
+ /**
+ * Package name of print spooler.
+ *
+ * @hide
+ */
+ public static final String PRINT_SPOOLER_PACKAGE_NAME = "com.android.printspooler";
+
+ /**
+ * Select enabled services.
+ * </p>
+ * @see #getPrintServices
+ * @hide
+ */
+ public static final int ENABLED_SERVICES = 1 << 0;
+
+ /**
+ * Select disabled services.
+ * </p>
+ * @see #getPrintServices
+ * @hide
+ */
+ public static final int DISABLED_SERVICES = 1 << 1;
+
+ /**
+ * Select all services.
+ * </p>
+ * @see #getPrintServices
+ * @hide
+ */
+ public static final int ALL_SERVICES = ENABLED_SERVICES | DISABLED_SERVICES;
/**
* The action for launching the print dialog activity.
@@ -165,7 +198,10 @@
private final Handler mHandler;
- private Map<PrintJobStateChangeListener, PrintJobStateChangeListenerWrapper> mPrintJobStateChangeListeners;
+ private Map<PrintJobStateChangeListener, PrintJobStateChangeListenerWrapper>
+ mPrintJobStateChangeListeners;
+ private Map<PrintServicesChangeListener, PrintServicesChangeListenerWrapper>
+ mPrintServicesChangeListeners;
/** @hide */
public interface PrintJobStateChangeListener {
@@ -178,6 +214,15 @@
public void onPrintJobStateChanged(PrintJobId printJobId);
}
+ /** @hide */
+ public interface PrintServicesChangeListener {
+
+ /**
+ * Callback notifying that the print services changed.
+ */
+ public void onPrintServicesChanged();
+ }
+
/**
* Creates a new instance.
*
@@ -207,6 +252,15 @@
}
args.recycle();
} break;
+ case MSG_NOTIFY_PRINT_SERVICES_CHANGED: {
+ PrintServicesChangeListenerWrapper wrapper =
+ (PrintServicesChangeListenerWrapper) message.obj;
+ PrintServicesChangeListener listener = wrapper.getListener();
+ if (listener != null) {
+ listener.onPrintServicesChanged();
+ }
+ } break;
+
}
}
};
@@ -478,42 +532,82 @@
}
/**
- * Gets the list of enabled print services.
+ * Listen for changes to the installed and enabled print services.
*
- * @return The enabled service list or an empty list.
- * @hide
+ * @param listener the listener to add
+ *
+ * @see android.print.PrintManager#getPrintServices
*/
- public List<PrintServiceInfo> getEnabledPrintServices() {
+ void addPrintServicesChangeListener(@NonNull PrintServicesChangeListener listener) {
if (mService == null) {
Log.w(LOG_TAG, "Feature android.software.print not available");
- return Collections.emptyList();
+ return;
}
+ if (mPrintServicesChangeListeners == null) {
+ mPrintServicesChangeListeners = new ArrayMap<PrintServicesChangeListener,
+ PrintServicesChangeListenerWrapper>();
+ }
+ PrintServicesChangeListenerWrapper wrappedListener =
+ new PrintServicesChangeListenerWrapper(listener, mHandler);
try {
- List<PrintServiceInfo> enabledServices = mService.getEnabledPrintServices(mUserId);
- if (enabledServices != null) {
- return enabledServices;
- }
+ mService.addPrintServicesChangeListener(wrappedListener, mUserId);
+ mPrintServicesChangeListeners.put(listener, wrappedListener);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
- return Collections.emptyList();
}
/**
- * Gets the list of installed print services.
+ * Stop listening for changes to the installed and enabled print services.
*
- * @return The installed service list or an empty list.
- * @hide
+ * @param listener the listener to remove
+ *
+ * @see android.print.PrintManager#getPrintServices
*/
- public List<PrintServiceInfo> getInstalledPrintServices() {
+ void removePrintServicesChangeListener(@NonNull PrintServicesChangeListener listener) {
if (mService == null) {
Log.w(LOG_TAG, "Feature android.software.print not available");
- return Collections.emptyList();
+ return;
}
+ if (mPrintServicesChangeListeners == null) {
+ return;
+ }
+ PrintServicesChangeListenerWrapper wrappedListener =
+ mPrintServicesChangeListeners.remove(listener);
+ if (wrappedListener == null) {
+ return;
+ }
+ if (mPrintServicesChangeListeners.isEmpty()) {
+ mPrintServicesChangeListeners = null;
+ }
+ wrappedListener.destroy();
try {
- List<PrintServiceInfo> installedServices = mService.getInstalledPrintServices(mUserId);
- if (installedServices != null) {
- return installedServices;
+ mService.removePrintServicesChangeListener(wrappedListener, mUserId);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error removing print services change listener", re);
+ }
+ }
+
+
+ /**
+ * Gets the list of print services, but does not register for updates. The user has to register
+ * for updates by itself, or use {@link PrintServicesLoader}.
+ *
+ * @param selectionFlags flags selecting which services to get. Either
+ * {@link #ENABLED_SERVICES},{@link #DISABLED_SERVICES}, or both.
+ *
+ * @return The enabled service list or an empty list.
+ *
+ * @see #addPrintServicesChangeListener(PrintServicesChangeListener)
+ * @see #removePrintServicesChangeListener(PrintServicesChangeListener)
+ *
+ * @hide
+ */
+ public @NonNull List<PrintServiceInfo> getPrintServices(int selectionFlags) {
+ try {
+ List<PrintServiceInfo> services = mService.getPrintServices(selectionFlags, mUserId);
+ if (services != null) {
+ return services;
}
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -533,6 +627,26 @@
}
/**
+ * Enable or disable a print service.
+ *
+ * @param service The service to enabled or disable
+ * @param isEnabled whether the service should be enabled or disabled
+ *
+ * @hide
+ */
+ public void setPrintServiceEnabled(@NonNull ComponentName service, boolean isEnabled) {
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return;
+ }
+ try {
+ mService.setPrintServiceEnabled(service, isEnabled, mUserId);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error enabling or disabling " + service, re);
+ }
+ }
+
+ /**
* @hide
*/
public static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub
@@ -1096,4 +1210,36 @@
return mWeakListener.get();
}
}
+
+ /**
+ * @hide
+ */
+ public static final class PrintServicesChangeListenerWrapper extends
+ IPrintServicesChangeListener.Stub {
+ private final WeakReference<PrintServicesChangeListener> mWeakListener;
+ private final WeakReference<Handler> mWeakHandler;
+
+ public PrintServicesChangeListenerWrapper(PrintServicesChangeListener listener,
+ Handler handler) {
+ mWeakListener = new WeakReference<>(listener);
+ mWeakHandler = new WeakReference<>(handler);
+ }
+
+ @Override
+ public void onPrintServicesChanged() {
+ Handler handler = mWeakHandler.get();
+ PrintServicesChangeListener listener = mWeakListener.get();
+ if (handler != null && listener != null) {
+ handler.obtainMessage(MSG_NOTIFY_PRINT_SERVICES_CHANGED, this).sendToTarget();
+ }
+ }
+
+ public void destroy() {
+ mWeakListener.clear();
+ }
+
+ public PrintServicesChangeListener getListener() {
+ return mWeakListener.get();
+ }
+ }
}
diff --git a/core/java/android/print/PrintServicesLoader.java b/core/java/android/print/PrintServicesLoader.java
new file mode 100644
index 0000000..ed41114
--- /dev/null
+++ b/core/java/android/print/PrintServicesLoader.java
@@ -0,0 +1,125 @@
+/*
+ * 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.print;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Loader;
+import android.os.Handler;
+import android.os.Message;
+import android.printservice.PrintServiceInfo;
+
+import java.util.List;
+
+/**
+ * Loader for the list of print services. Can be parametrized to select a subset.
+ *
+ * @hide
+ */
+public class PrintServicesLoader extends Loader<List<PrintServiceInfo>> {
+ /** What type of services to load. */
+ private final int mSelectionFlags;
+
+ /** The print manager to be used by this object */
+ private final @NonNull PrintManager mPrintManager;
+
+ /** Handler to sequentialize the delivery of the results to the main thread */
+ private Handler mHandler;
+
+ /** Listens for updates to the data from the platform */
+ private PrintManager.PrintServicesChangeListener mListener;
+
+ /**
+ * Create a new PrintServicesLoader.
+ *
+ * @param selectionFlags What type of services to load.
+ */
+ public PrintServicesLoader(@NonNull PrintManager printManager, @NonNull Context context,
+ int selectionFlags) {
+ super(context);
+ mPrintManager = printManager;
+ mSelectionFlags = selectionFlags;
+ }
+
+ @Override
+ protected void onForceLoad() {
+ queueNewResult();
+ }
+
+ /**
+ * Read the print services and queue it to be delivered on the main thread.
+ */
+ private void queueNewResult() {
+ Message m = mHandler.obtainMessage(0);
+ m.obj = mPrintManager.getPrintServices(mSelectionFlags);
+ mHandler.sendMessage(m);
+ }
+
+ @Override
+ protected void onStartLoading() {
+ mHandler = new MyHandler();
+ mListener = new PrintManager.PrintServicesChangeListener() {
+ @Override public void onPrintServicesChanged() {
+ queueNewResult();
+ }
+ };
+
+ mPrintManager.addPrintServicesChangeListener(mListener);
+
+ // Immediately deliver a result
+ deliverResult(mPrintManager.getPrintServices(mSelectionFlags));
+ }
+
+ @Override
+ protected void onStopLoading() {
+ if (mListener != null) {
+ mPrintManager.removePrintServicesChangeListener(mListener);
+ mListener = null;
+ }
+
+ if (mHandler != null) {
+ mHandler.removeMessages(0);
+ mHandler = null;
+ }
+ }
+
+ @Override
+ protected void onReset() {
+ onStopLoading();
+ }
+
+ /**
+ * Handler to sequentialize all the updates to the main thread.
+ */
+ private class MyHandler extends Handler {
+ /**
+ * Create a new handler on the main thread.
+ */
+ public MyHandler() {
+ super(getContext().getMainLooper());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+
+ if (isStarted()) {
+ deliverResult((List<PrintServiceInfo>) msg.obj);
+ }
+ }
+ }
+}
diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java
index 91e01f2..45e3d47 100644
--- a/core/java/android/printservice/PrintServiceInfo.java
+++ b/core/java/android/printservice/PrintServiceInfo.java
@@ -55,6 +55,8 @@
private final String mId;
+ private boolean mIsEnabled;
+
private final ResolveInfo mResolveInfo;
private final String mSettingsActivityName;
@@ -70,6 +72,7 @@
*/
public PrintServiceInfo(Parcel parcel) {
mId = parcel.readString();
+ mIsEnabled = parcel.readByte() != 0;
mResolveInfo = parcel.readParcelable(null);
mSettingsActivityName = parcel.readString();
mAddPrintersActivityName = parcel.readString();
@@ -180,6 +183,24 @@
}
/**
+ * If the service was enabled when it was read from the system.
+ *
+ * @return The id.
+ */
+ public boolean isEnabled() {
+ return mIsEnabled;
+ }
+
+ /**
+ * Mark a service as enabled or not
+ *
+ * @param isEnabled If the service should be marked as enabled.
+ */
+ public void setIsEnabled(boolean isEnabled) {
+ mIsEnabled = isEnabled;
+ }
+
+ /**
* The service {@link ResolveInfo}.
*
* @return The info.
@@ -238,6 +259,7 @@
@Override
public void writeToParcel(Parcel parcel, int flagz) {
parcel.writeString(mId);
+ parcel.writeByte((byte)(mIsEnabled ? 1 : 0));
parcel.writeParcelable(mResolveInfo, 0);
parcel.writeString(mSettingsActivityName);
parcel.writeString(mAddPrintersActivityName);
@@ -276,6 +298,7 @@
StringBuilder builder = new StringBuilder();
builder.append("PrintServiceInfo{");
builder.append("id=").append(mId);
+ builder.append("isEnabled=").append(mIsEnabled);
builder.append(", resolveInfo=").append(mResolveInfo);
builder.append(", settingsActivityName=").append(mSettingsActivityName);
builder.append(", addPrintersActivityName=").append(mAddPrintersActivityName);
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 3700098..0065cd9 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -93,9 +93,6 @@
public static final String EXTRA_PACKAGE_NAME = "android.content.extra.PACKAGE_NAME";
/** {@hide} */
- public static final String EXTRA_SHOW_ADVANCED = "android.content.extra.SHOW_ADVANCED";
-
- /** {@hide} */
public static final String EXTRA_SHOW_FILESIZE = "android.content.extra.SHOW_FILESIZE";
/** {@hide} */
@@ -481,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)
*/
@@ -564,22 +560,29 @@
public static final int FLAG_EMPTY = 1 << 16;
/**
- * Flag indicating that this root should only be visible to advanced
- * users.
- *
- * @see #COLUMN_FLAGS
- * @hide
- */
- public static final int FLAG_ADVANCED = 1 << 17;
-
- /**
* Flag indicating that this root has settings.
*
* @see #COLUMN_FLAGS
* @see DocumentsContract#ACTION_DOCUMENT_ROOT_SETTINGS
* @hide
*/
- public static final int FLAG_HAS_SETTINGS = 1 << 18;
+ 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..d43ff4e 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1241,6 +1241,32 @@
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";
+
+ /**
+ * Activity Action: Show VR listener settings.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ *
+ * @see android.service.vr.VrListenerService
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_VR_LISTENER_SETTINGS
+ = "android.settings.VR_LISTENER_SETTINGS";
+
// End of Intent actions for Settings
/**
@@ -4522,6 +4548,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 ':'.
@@ -5834,15 +5867,6 @@
public static final String ASSIST_SCREENSHOT_ENABLED = "assist_screenshot_enabled";
/**
- * Names of the service component that the current user has explicitly allowed to
- * see and change the importance of all of the user's notifications.
- *
- * @hide
- */
- public static final String ENABLED_NOTIFICATION_ASSISTANT
- = "enabled_notification_assistant";
-
- /**
* Names of the service components that the current user has explicitly allowed to
* see all of the user's notifications, separated by ':'.
*
@@ -6021,6 +6045,14 @@
public static final String BRIGHTNESS_USE_TWILIGHT = "brightness_use_twilight";
/**
+ * Names of the service components that the current user has explicitly allowed to
+ * be a VR mode listener, separated by ':'.
+ *
+ * @hide
+ */
+ public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -6047,6 +6079,7 @@
BACKUP_AUTO_RESTORE,
ENABLED_ACCESSIBILITY_SERVICES,
ENABLED_NOTIFICATION_LISTENERS,
+ ENABLED_VR_LISTENERS,
ENABLED_INPUT_METHODS,
TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
TOUCH_EXPLORATION_ENABLED,
@@ -8240,6 +8273,13 @@
"allow_user_switching_when_system_user_locked";
/**
+ * Boot count since the device starts running APK level 24.
+ * <p>
+ * Type: int
+ */
+ public static final String BOOT_COUNT = "boot_count";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
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/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index a0de17f..8c35901 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -23,7 +23,7 @@
/** @hide */
oneway interface INotificationListener
{
- // listeners and assistants
+ // listeners and rankers
void onListenerConnected(in NotificationRankingUpdate update);
void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
in NotificationRankingUpdate update);
@@ -33,7 +33,7 @@
void onListenerHintsChanged(int hints);
void onInterruptionFilterChanged(int interruptionFilter);
- // assistants only
+ // rankers only
void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user);
void onNotificationVisibilityChanged(String key, long time, boolean visible);
void onNotificationClick(String key, long time);
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 73a890f..a8b8da1 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -69,16 +69,6 @@
* <action android:name="android.service.notification.NotificationListenerService" />
* </intent-filter>
* </service></pre>
- * <p> Typically, while enabled in user settings, this service will be bound on boot or when a
- * settings change occurs that could affect whether this service should run. However, for some
- * system usage modes, the you may instead specify that this service is instead bound and unbound
- * in response to mode changes by including a category in the intent filter. Currently
- * supported categories are:
- * <ul>
- * <li>{@link #CATEGORY_VR_NOTIFICATIONS} - this service is bound when an Activity has enabled
- * VR mode. {@see android.app.Activity#setVrMode(boolean)}.</li>
- * </ul>
- * </p>
*/
public abstract class NotificationListenerService extends Service {
// TAG = "NotificationListenerService[MySubclass]"
@@ -180,13 +170,18 @@
private INotificationManager mNoMan;
- /** Only valid after a successful call to (@link registerAsService}. */
- private int mCurrentUser;
+ /**
+ * Only valid after a successful call to (@link registerAsService}.
+ * @hide
+ */
+ protected int mCurrentUser;
-
- // This context is required for system services since NotificationListenerService isn't
- // started as a real Service and hence no context is available.
- private Context mSystemContext;
+ /**
+ * This context is required for system services since NotificationListenerService isn't
+ * started as a real Service and hence no context is available..
+ * @hide
+ */
+ protected Context mSystemContext;
/**
* The {@link Intent} that must be declared as handled by the service.
@@ -195,17 +190,6 @@
public static final String SERVICE_INTERFACE
= "android.service.notification.NotificationListenerService";
- /**
- * If this category is declared in the application manifest for a service of this type, this
- * service will be bound when VR mode is enabled, and unbound when VR mode is disabled rather
- * than the normal lifecycle for a notification service.
- *
- * {@see android.app.Activity#setVrMode(boolean)}
- */
- @SdkConstant(SdkConstant.SdkConstantType.INTENT_CATEGORY)
- public static final String CATEGORY_VR_NOTIFICATIONS =
- "android.intent.category.vr.notifications";
-
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
@@ -696,12 +680,18 @@
@SystemApi
public void registerAsSystemService(Context context, ComponentName componentName,
int currentUser) throws RemoteException {
+ registerAsSystemServiceImpl(context, componentName, currentUser, false /* asRanker */);
+ }
+
+ /** @hide */
+ protected void registerAsSystemServiceImpl(Context context, ComponentName componentName,
+ int currentUser, boolean asRanker) throws RemoteException {
mSystemContext = context;
if (mWrapper == null) {
mWrapper = new NotificationListenerWrapper();
}
INotificationManager noMan = getNotificationInterface();
- noMan.registerListener(mWrapper, componentName, currentUser);
+ noMan.registerListener(mWrapper, componentName, currentUser, asRanker);
mCurrentUser = currentUser;
mHandler = new MyHandler(context.getMainLooper());
}
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationRankerService.java
similarity index 90%
rename from core/java/android/service/notification/NotificationAssistantService.java
rename to core/java/android/service/notification/NotificationRankerService.java
index 41af837..520b4c2 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationRankerService.java
@@ -31,31 +31,20 @@
import com.android.internal.os.SomeArgs;
/**
- * A service that helps the user manage notifications by modifying the
- * relative importance of notifications.
- * <p>To extend this class, you must declare the service in your manifest file with
- * the {@link android.Manifest.permission#BIND_NOTIFICATION_ASSISTANT_SERVICE} permission
- * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
- * <pre>
- * <service android:name=".NotificationAssistant"
- * android:label="@string/service_name"
- * android:permission="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE">
- * <intent-filter>
- * <action android:name="android.service.notification.NotificationAssistantService" />
- * </intent-filter>
- * </service></pre>
+ * A service that helps the user manage notifications. This class is only used to
+ * extend the framework service and may not be implemented by non-framework components.
* @hide
*/
@SystemApi
-public abstract class NotificationAssistantService extends NotificationListenerService {
- private static final String TAG = "NotificationAssistant";
+public abstract class NotificationRankerService extends NotificationListenerService {
+ private static final String TAG = "NotificationRanker";
/**
* The {@link Intent} that must be declared as handled by the service.
*/
@SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
public static final String SERVICE_INTERFACE
- = "android.service.notification.NotificationAssistantService";
+ = "android.service.notification.NotificationRankerService";
/** Notification was canceled by the status bar reporting a click. */
public static final int REASON_DELEGATE_CLICK = 1;
@@ -130,7 +119,7 @@
@Override
public void registerAsSystemService(Context context, ComponentName componentName,
int currentUser) throws RemoteException {
- super.registerAsSystemService(context, componentName, currentUser);
+ registerAsSystemServiceImpl(context, componentName, currentUser, true /* as Ranker */);
mHandler = new MyHandler(getContext().getMainLooper());
}
@@ -143,7 +132,7 @@
@Override
public final IBinder onBind(Intent intent) {
if (mWrapper == null) {
- mWrapper = new NotificationAssistantWrapper();
+ mWrapper = new NotificationRankingServiceWrapper();
}
return mWrapper;
}
@@ -216,14 +205,14 @@
public final void adjustImportance(String key, Adjustment adjustment) {
if (!isBound()) return;
try {
- getNotificationInterface().setImportanceFromAssistant(mWrapper, key,
+ getNotificationInterface().setImportanceFromRankerService(mWrapper, key,
adjustment.mImportance, adjustment.mExplanation);
} catch (android.os.RemoteException ex) {
Log.v(TAG, "Unable to contact notification manager", ex);
}
}
- private class NotificationAssistantWrapper extends NotificationListenerWrapper {
+ private class NotificationRankingServiceWrapper extends NotificationListenerWrapper {
@Override
public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
int importance, boolean user) {
diff --git a/core/java/android/hardware/CameraInfo.aidl b/core/java/android/service/vr/IVrListener.aidl
similarity index 75%
rename from core/java/android/hardware/CameraInfo.aidl
rename to core/java/android/service/vr/IVrListener.aidl
index e21e694..b7273ba 100644
--- a/core/java/android/hardware/CameraInfo.aidl
+++ b/core/java/android/service/vr/IVrListener.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2013 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.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-package android.hardware;
+package android.service.vr;
/** @hide */
-parcelable CameraInfo;
+oneway interface IVrListener {
+
+}
\ No newline at end of file
diff --git a/core/java/android/service/vr/VrListenerService.java b/core/java/android/service/vr/VrListenerService.java
new file mode 100644
index 0000000..5f1f659
--- /dev/null
+++ b/core/java/android/service/vr/VrListenerService.java
@@ -0,0 +1,88 @@
+/**
+ * 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.service.vr;
+
+import android.annotation.NonNull;
+import android.annotation.SdkConstant;
+import android.app.ActivityManager;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * A service that is bound from the system while running in virtual reality (VR) mode.
+ *
+ * <p>To extend this class, you must declare the service in your manifest file with
+ * the {@link android.Manifest.permission#BIND_VR_LISTENER_SERVICE} permission
+ * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
+ * <pre>
+ * <service android:name=".VrListener"
+ * android:label="@string/service_name"
+ * android:permission="android.permission.BIND_VR_LISTENER_SERVICE">
+ * <intent-filter>
+ * <action android:name="android.service.vr.VrListenerService" />
+ * </intent-filter>
+ * </service>
+ * </pre>
+ *
+ * <p>
+ * This service is bound when the system enters VR mode and is unbound when the system leaves VR
+ * mode.
+ * {@see android.app.Activity#setVrMode(boolean)}
+ * </p>
+ */
+public abstract class VrListenerService extends Service {
+
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE = "android.service.vr.VrListenerService";
+
+ /**
+ * @hide
+ */
+ public static class VrListenerBinder extends IVrListener.Stub {
+ }
+
+ private final VrListenerBinder mBinder = new VrListenerBinder();
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ /**
+ * Check if the given package is available to be enabled/disabled in VR mode settings.
+ *
+ * @param context the {@link Context} to use for looking up the requested component.
+ * @param requestedComponent the name of the component that implements
+ * {@link android.service.vr.VrListenerService} to check.
+ *
+ * @return {@code true} if this package is enabled in settings.
+ */
+ public static final boolean isVrModePackageEnabled(@NonNull Context context,
+ @NonNull ComponentName requestedComponent) {
+ ActivityManager am = context.getSystemService(ActivityManager.class);
+ if (am == null) {
+ return false;
+ }
+ return am.isVrModePackageEnabled(requestedComponent);
+ }
+}
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/transition/Slide.java b/core/java/android/transition/Slide.java
index 9af65e4..2645f86 100644
--- a/core/java/android/transition/Slide.java
+++ b/core/java/android/transition/Slide.java
@@ -47,6 +47,7 @@
private static final String PROPNAME_SCREEN_POSITION = "android:slide:screenPosition";
private CalculateSlide mSlideCalculator = sCalculateBottom;
private @GravityFlag int mSlideEdge = Gravity.BOTTOM;
+ private float mSlideFraction = 1;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -56,16 +57,16 @@
private interface CalculateSlide {
/** Returns the translation value for view when it goes out of the scene */
- float getGoneX(ViewGroup sceneRoot, View view);
+ float getGoneX(ViewGroup sceneRoot, View view, float fraction);
/** Returns the translation value for view when it goes out of the scene */
- float getGoneY(ViewGroup sceneRoot, View view);
+ float getGoneY(ViewGroup sceneRoot, View view, float fraction);
}
private static abstract class CalculateSlideHorizontal implements CalculateSlide {
@Override
- public float getGoneY(ViewGroup sceneRoot, View view) {
+ public float getGoneY(ViewGroup sceneRoot, View view, float fraction) {
return view.getTranslationY();
}
}
@@ -73,27 +74,27 @@
private static abstract class CalculateSlideVertical implements CalculateSlide {
@Override
- public float getGoneX(ViewGroup sceneRoot, View view) {
+ public float getGoneX(ViewGroup sceneRoot, View view, float fraction) {
return view.getTranslationX();
}
}
private static final CalculateSlide sCalculateLeft = new CalculateSlideHorizontal() {
@Override
- public float getGoneX(ViewGroup sceneRoot, View view) {
- return view.getTranslationX() - sceneRoot.getWidth();
+ public float getGoneX(ViewGroup sceneRoot, View view, float fraction) {
+ return view.getTranslationX() - sceneRoot.getWidth() * fraction;
}
};
private static final CalculateSlide sCalculateStart = new CalculateSlideHorizontal() {
@Override
- public float getGoneX(ViewGroup sceneRoot, View view) {
+ public float getGoneX(ViewGroup sceneRoot, View view, float fraction) {
final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
final float x;
if (isRtl) {
- x = view.getTranslationX() + sceneRoot.getWidth();
+ x = view.getTranslationX() + sceneRoot.getWidth() * fraction;
} else {
- x = view.getTranslationX() - sceneRoot.getWidth();
+ x = view.getTranslationX() - sceneRoot.getWidth() * fraction;
}
return x;
}
@@ -101,27 +102,27 @@
private static final CalculateSlide sCalculateTop = new CalculateSlideVertical() {
@Override
- public float getGoneY(ViewGroup sceneRoot, View view) {
- return view.getTranslationY() - sceneRoot.getHeight();
+ public float getGoneY(ViewGroup sceneRoot, View view, float fraction) {
+ return view.getTranslationY() - sceneRoot.getHeight() * fraction;
}
};
private static final CalculateSlide sCalculateRight = new CalculateSlideHorizontal() {
@Override
- public float getGoneX(ViewGroup sceneRoot, View view) {
- return view.getTranslationX() + sceneRoot.getWidth();
+ public float getGoneX(ViewGroup sceneRoot, View view, float fraction) {
+ return view.getTranslationX() + sceneRoot.getWidth() * fraction;
}
};
private static final CalculateSlide sCalculateEnd = new CalculateSlideHorizontal() {
@Override
- public float getGoneX(ViewGroup sceneRoot, View view) {
+ public float getGoneX(ViewGroup sceneRoot, View view, float fraction) {
final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
final float x;
if (isRtl) {
- x = view.getTranslationX() - sceneRoot.getWidth();
+ x = view.getTranslationX() - sceneRoot.getWidth() * fraction;
} else {
- x = view.getTranslationX() + sceneRoot.getWidth();
+ x = view.getTranslationX() + sceneRoot.getWidth() * fraction;
}
return x;
}
@@ -129,8 +130,8 @@
private static final CalculateSlide sCalculateBottom = new CalculateSlideVertical() {
@Override
- public float getGoneY(ViewGroup sceneRoot, View view) {
- return view.getTranslationY() + sceneRoot.getHeight();
+ public float getGoneY(ViewGroup sceneRoot, View view, float fraction) {
+ return view.getTranslationY() + sceneRoot.getHeight() * fraction;
}
};
@@ -237,8 +238,8 @@
int[] position = (int[]) endValues.values.get(PROPNAME_SCREEN_POSITION);
float endX = view.getTranslationX();
float endY = view.getTranslationY();
- float startX = mSlideCalculator.getGoneX(sceneRoot, view);
- float startY = mSlideCalculator.getGoneY(sceneRoot, view);
+ float startX = mSlideCalculator.getGoneX(sceneRoot, view, mSlideFraction);
+ float startY = mSlideCalculator.getGoneY(sceneRoot, view, mSlideFraction);
return TranslationAnimationCreator
.createAnimation(view, endValues, position[0], position[1],
startX, startY, endX, endY, sDecelerate, this);
@@ -253,10 +254,15 @@
int[] position = (int[]) startValues.values.get(PROPNAME_SCREEN_POSITION);
float startX = view.getTranslationX();
float startY = view.getTranslationY();
- float endX = mSlideCalculator.getGoneX(sceneRoot, view);
- float endY = mSlideCalculator.getGoneY(sceneRoot, view);
+ float endX = mSlideCalculator.getGoneX(sceneRoot, view, mSlideFraction);
+ float endY = mSlideCalculator.getGoneY(sceneRoot, view, mSlideFraction);
return TranslationAnimationCreator
.createAnimation(view, startValues, position[0], position[1],
startX, startY, endX, endY, sAccelerate, this);
}
+
+ /** @hide */
+ public void setSlideFraction(float slideFraction) {
+ mSlideFraction = slideFraction;
+ }
}
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index bdb1fdc..92a5803 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -67,7 +67,7 @@
/**
* @hide Special immutable empty ArrayMap.
*/
- public static final ArrayMap EMPTY = new ArrayMap(true);
+ public static final ArrayMap EMPTY = new ArrayMap<>(-1);
/**
* Caches of small array objects to avoid spamming garbage. The cache
@@ -80,6 +80,7 @@
static Object[] mTwiceBaseCache;
static int mTwiceBaseCacheSize;
+ final boolean mIdentityHashCode;
int[] mHashes;
Object[] mArray;
int mSize;
@@ -236,16 +237,27 @@
* will grow once items are added to it.
*/
public ArrayMap() {
- mHashes = EmptyArray.INT;
- mArray = EmptyArray.OBJECT;
- mSize = 0;
+ this(0, false);
}
/**
* Create a new ArrayMap with a given initial capacity.
*/
public ArrayMap(int capacity) {
- if (capacity == 0) {
+ this(capacity, false);
+ }
+
+ /** {@hide} */
+ public ArrayMap(int capacity, boolean identityHashCode) {
+ mIdentityHashCode = identityHashCode;
+
+ // If this is immutable, use the sentinal EMPTY_IMMUTABLE_INTS
+ // instance instead of the usual EmptyArray.INT. The reference
+ // is checked later to see if the array is allowed to grow.
+ if (capacity < 0) {
+ mHashes = EMPTY_IMMUTABLE_INTS;
+ mArray = EmptyArray.OBJECT;
+ } else if (capacity == 0) {
mHashes = EmptyArray.INT;
mArray = EmptyArray.OBJECT;
} else {
@@ -254,15 +266,6 @@
mSize = 0;
}
- private ArrayMap(boolean immutable) {
- // If this is immutable, use the sentinal EMPTY_IMMUTABLE_INTS
- // instance instead of the usual EmptyArray.INT. The reference
- // is checked later to see if the array is allowed to grow.
- mHashes = immutable ? EMPTY_IMMUTABLE_INTS : EmptyArray.INT;
- mArray = EmptyArray.OBJECT;
- mSize = 0;
- }
-
/**
* Create a new ArrayMap with the mappings from the given ArrayMap.
*/
@@ -336,7 +339,8 @@
* @return Returns the index of the key if it exists, else a negative integer.
*/
public int indexOfKey(Object key) {
- return key == null ? indexOfNull() : indexOf(key, key.hashCode());
+ return key == null ? indexOfNull()
+ : indexOf(key, mIdentityHashCode ? System.identityHashCode(key) : key.hashCode());
}
int indexOfValue(Object value) {
@@ -437,7 +441,7 @@
hash = 0;
index = indexOfNull();
} else {
- hash = key.hashCode();
+ hash = mIdentityHashCode ? System.identityHashCode(key) : key.hashCode();
index = indexOf(key, hash);
}
if (index >= 0) {
@@ -488,7 +492,8 @@
*/
public void append(K key, V value) {
int index = mSize;
- final int hash = key == null ? 0 : key.hashCode();
+ final int hash = key == null ? 0
+ : (mIdentityHashCode ? System.identityHashCode(key) : key.hashCode());
if (index >= mHashes.length) {
throw new IllegalStateException("Array is full");
}
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index b7a3c42..9e9314f 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -69,6 +69,7 @@
static Object[] mTwiceBaseCache;
static int mTwiceBaseCacheSize;
+ final boolean mIdentityHashCode;
int[] mHashes;
Object[] mArray;
int mSize;
@@ -222,15 +223,19 @@
* will grow once items are added to it.
*/
public ArraySet() {
- mHashes = EmptyArray.INT;
- mArray = EmptyArray.OBJECT;
- mSize = 0;
+ this(0, false);
}
/**
* Create a new ArraySet with a given initial capacity.
*/
public ArraySet(int capacity) {
+ this(capacity, false);
+ }
+
+ /** {@hide} */
+ public ArraySet(int capacity, boolean identityHashCode) {
+ mIdentityHashCode = identityHashCode;
if (capacity == 0) {
mHashes = EmptyArray.INT;
mArray = EmptyArray.OBJECT;
@@ -306,7 +311,8 @@
* @return Returns the index of the value if it exists, else a negative integer.
*/
public int indexOf(Object key) {
- return key == null ? indexOfNull() : indexOf(key, key.hashCode());
+ return key == null ? indexOfNull()
+ : indexOf(key, mIdentityHashCode ? System.identityHashCode(key) : key.hashCode());
}
/**
@@ -343,7 +349,7 @@
hash = 0;
index = indexOfNull();
} else {
- hash = value.hashCode();
+ hash = mIdentityHashCode ? System.identityHashCode(value) : value.hashCode();
index = indexOf(value, hash);
}
if (index >= 0) {
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/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index b9a7421..cff9d8e 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -35,7 +35,6 @@
public class NotificationHeaderView extends ViewGroup {
public static final int NO_COLOR = -1;
private final int mChildMinWidth;
- private final int mExpandTopPadding;
private final int mContentEndMargin;
private View mAppName;
private View mSubTextView;
@@ -43,12 +42,10 @@
private HeaderTouchListener mTouchListener = new HeaderTouchListener();
private ImageView mExpandButton;
private View mIcon;
- private TextView mChildCount;
private View mProfileBadge;
private View mInfo;
private int mIconColor;
private int mOriginalNotificationColor;
- private boolean mGroupHeader;
private boolean mExpanded;
private boolean mShowWorkBadgeAtEnd;
@@ -70,7 +67,6 @@
com.android.internal.R.dimen.notification_header_shrink_min_width);
mContentEndMargin = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_content_margin_end);
- mExpandTopPadding = (int) (1 * getResources().getDisplayMetrics().density);
}
@Override
@@ -80,7 +76,6 @@
mSubTextView = findViewById(com.android.internal.R.id.header_sub_text);
mExpandButton = (ImageView) findViewById(com.android.internal.R.id.expand_button);
mIcon = findViewById(com.android.internal.R.id.icon);
- mChildCount = (TextView) findViewById(com.android.internal.R.id.number_of_children);
mProfileBadge = findViewById(com.android.internal.R.id.profile_badge);
mInfo = findViewById(com.android.internal.R.id.header_content_info);
}
@@ -193,17 +188,6 @@
updateTouchListener();
}
- public void setChildCount(int childCount) {
- if (childCount > 0) {
- mChildCount.setText(getContext().getString(
- com.android.internal.R.string.notification_children_count_bracketed,
- childCount));
- mChildCount.setVisibility(VISIBLE);
- } else {
- mChildCount.setVisibility(GONE);
- }
- }
-
@RemotableViewMethod
public void setOriginalIconColor(int color) {
mIconColor = color;
@@ -222,11 +206,6 @@
return mOriginalNotificationColor;
}
- public void setIsGroupHeader(boolean isGroupHeader) {
- mGroupHeader = isGroupHeader;
- updateExpandButton();
- }
-
@RemotableViewMethod
public void setExpanded(boolean expanded) {
mExpanded = expanded;
@@ -235,24 +214,13 @@
private void updateExpandButton() {
int drawableId;
- int paddingTop = 0;
- if (mGroupHeader) {
- if (mExpanded) {
- drawableId = com.android.internal.R.drawable.ic_collapse_bundle;
- } else {
- drawableId =com.android.internal.R.drawable.ic_expand_bundle;
- }
+ if (mExpanded) {
+ drawableId = com.android.internal.R.drawable.ic_collapse_notification;
} else {
- if (mExpanded) {
- drawableId = com.android.internal.R.drawable.ic_collapse_notification;
- } else {
- drawableId = com.android.internal.R.drawable.ic_expand_notification;
- }
- paddingTop = mExpandTopPadding;
+ drawableId = com.android.internal.R.drawable.ic_expand_notification;
}
mExpandButton.setImageDrawable(getContext().getDrawable(drawableId));
mExpandButton.setColorFilter(mOriginalNotificationColor);
- mExpandButton.setPadding(0, paddingTop, 0, 0);
}
public void setShowWorkBadgeAtEnd(boolean showWorkBadgeAtEnd) {
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/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index afe2f10..f7405e2 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1078,8 +1078,7 @@
scheduleTraversals();
} else {
if (mAttachInfo.mHardwareRenderer != null) {
- // TODO: Temporary to help track down b/27286867
- Log.d(mTag, "WindowStopped on " + getTitle());
+ if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle());
mAttachInfo.mHardwareRenderer.updateSurface(null);
mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
}
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/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 4c015ba..859df43 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -664,7 +664,7 @@
try {
return mService.getInputMethodList();
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -672,7 +672,7 @@
try {
return mService.getEnabledInputMethodList();
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -689,7 +689,7 @@
return mService.getEnabledInputMethodSubtypeList(
imi == null ? null : imi.getId(), allowsImplicitlySelectedSubtypes);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -697,7 +697,7 @@
try {
mService.updateStatusIcon(imeToken, packageName, iconId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -705,7 +705,7 @@
try {
mService.updateStatusIcon(imeToken, null, 0);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -714,7 +714,7 @@
try {
mService.setImeWindowStatus(imeToken, vis, backDisposition);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -728,7 +728,7 @@
try {
mService.registerSuggestionSpansForNotification(spans);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -737,7 +737,7 @@
try {
mService.notifySuggestionPicked(span, originalString, index);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -833,6 +833,7 @@
try {
mService.finishInput(mClient);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
notifyInputConnectionFinished();
@@ -996,9 +997,8 @@
try {
return mService.showSoftInput(mClient, flags, resultReceiver);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
-
- return false;
}
}
@@ -1007,6 +1007,7 @@
try {
mService.showSoftInput(mClient, flags, resultReceiver);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1065,8 +1066,8 @@
try {
return mService.hideSoftInput(mClient, flags, resultReceiver);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return false;
}
}
@@ -1421,6 +1422,7 @@
try {
mService.hideSoftInput(mClient, HIDE_NOT_ALWAYS, null);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1476,6 +1478,7 @@
rootView.getWindowToken(), controlFlags, softInputMode, windowFlags, null,
null);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1716,7 +1719,7 @@
try {
mService.setInputMethod(token, id);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1733,7 +1736,7 @@
try {
mService.setInputMethodAndSubtype(token, id, subtype);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1753,7 +1756,7 @@
try {
mService.hideMySoftInput(token, flags);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1774,7 +1777,7 @@
try {
mService.showMySoftInput(token, flags);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1980,7 +1983,7 @@
SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES;
mService.showInputMethodPickerFromClient(mClient, mode);
} catch (RemoteException e) {
- Log.w(TAG, "IME died: " + mCurId, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1989,7 +1992,7 @@
try {
mService.showInputMethodPickerFromClient(mClient, SHOW_IM_PICKER_MODE_AUTO);
} catch (RemoteException e) {
- Log.w(TAG, "IME died: " + mCurId, e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2003,7 +2006,7 @@
try {
mService.showInputMethodAndSubtypeEnablerFromClient(mClient, imiId);
} catch (RemoteException e) {
- Log.w(TAG, "IME died: " + mCurId, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2018,8 +2021,7 @@
try {
return mService.getCurrentInputMethodSubtype();
} catch (RemoteException e) {
- Log.w(TAG, "IME died: " + mCurId, e);
- return null;
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2036,8 +2038,7 @@
try {
return mService.setCurrentInputMethodSubtype(subtype);
} catch (RemoteException e) {
- Log.w(TAG, "IME died: " + mCurId, e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2071,7 +2072,7 @@
mLastSentUserActionNotificationSequenceNumber =
mNextUserActionNotificationSequenceNumber;
} catch (RemoteException e) {
- Log.w(TAG, "IME died: " + mCurId, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2104,7 +2105,7 @@
}
}
} catch (RemoteException e) {
- Log.w(TAG, "IME died: " + mCurId, e);
+ throw e.rethrowFromSystemServer();
}
return ret;
}
@@ -2119,8 +2120,7 @@
try {
return mService.getInputMethodWindowVisibleHeight();
} catch (RemoteException e) {
- Log.w(TAG, "IME died: " + mCurId, e);
- return 0;
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2139,8 +2139,7 @@
try {
return mService.switchToLastInputMethod(imeToken);
} catch (RemoteException e) {
- Log.w(TAG, "IME died: " + mCurId, e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2160,8 +2159,7 @@
try {
return mService.switchToNextInputMethod(imeToken, onlyCurrentIme);
} catch (RemoteException e) {
- Log.w(TAG, "IME died: " + mCurId, e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2182,8 +2180,7 @@
try {
return mService.shouldOfferSwitchingToNextInputMethod(imeToken);
} catch (RemoteException e) {
- Log.w(TAG, "IME died: " + mCurId, e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2218,7 +2215,7 @@
try {
mService.setAdditionalInputMethodSubtypes(imiId, subtypes);
} catch (RemoteException e) {
- Log.w(TAG, "IME died: " + mCurId, e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2228,8 +2225,7 @@
try {
return mService.getLastInputMethodSubtype();
} catch (RemoteException e) {
- Log.w(TAG, "IME died: " + mCurId, e);
- return null;
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 496f7ee..d2aef0a 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3078,7 +3078,8 @@
final int motionPosition = mClickMotionPosition;
if (adapter != null && mItemCount > 0 &&
motionPosition != INVALID_POSITION &&
- motionPosition < adapter.getCount() && sameWindow()) {
+ motionPosition < adapter.getCount() && sameWindow() &&
+ adapter.isEnabled(motionPosition)) {
final View view = getChildAt(motionPosition - mFirstPosition);
// If there is no view, something bad happened (the view scrolled off the
// screen, etc.) and we should cancel the click
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..406dc2b 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 mPreserveSelection;
boolean mTemporaryDetach;
boolean mIsBeingLongClicked;
@@ -351,10 +351,14 @@
}
void replace() {
+ if (mSuggestionsPopupWindow == null) {
+ mSuggestionsPopupWindow = new SuggestionsPopupWindow();
+ }
+ hideCursorAndSpanControllers();
+ mSuggestionsPopupWindow.show();
+
int middle = (mTextView.getSelectionStart() + mTextView.getSelectionEnd()) / 2;
- stopTextActionMode();
Selection.setSelection((Spannable) mTextView.getText(), middle);
- showSuggestions();
}
void onAttachedToWindow() {
@@ -377,13 +381,7 @@
updateSpellCheckSpans(0, mTextView.getText().length(),
true /* create the spell checker if needed */);
- if (mTextView.hasTransientState() &&
- mTextView.getSelectionStart() != mTextView.getSelectionEnd()) {
- // Since transient state is reference counted make sure it stays matched
- // with our own calls to it for managing selection.
- // The action mode callback will set this back again when/if the action mode starts.
- mTextView.setHasTransientState(false);
-
+ if (mTextView.getSelectionStart() != mTextView.getSelectionEnd()) {
// We had an active selection from before, start the selection mode.
startSelectionActionMode();
}
@@ -429,10 +427,8 @@
mSpellChecker = null;
}
- mPreserveDetachedSelection = true;
hideCursorAndSpanControllers();
- stopTextActionMode();
- mPreserveDetachedSelection = false;
+ stopTextActionModeWithPreservingSelection();
mTemporaryDetach = false;
}
@@ -1104,7 +1100,6 @@
mInsertionControllerEnabled) {
final int offset = mTextView.getOffsetForPosition(mLastDownPositionX,
mLastDownPositionY);
- stopTextActionMode();
Selection.setSelection((Spannable) mTextView.getText(), offset);
getInsertionController().show();
mIsInsertionActionModeStartPending = true;
@@ -1208,18 +1203,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 +1282,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 +1294,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 +1844,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 +1899,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 +1925,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();
@@ -2087,7 +2091,7 @@
mShowSuggestionRunnable = new Runnable() {
public void run() {
- showSuggestions();
+ replace();
}
};
// removeCallbacks is performed on every touch
@@ -2107,6 +2111,12 @@
}
}
+ private void stopTextActionModeWithPreservingSelection() {
+ mPreserveSelection = true;
+ stopTextActionMode();
+ mPreserveSelection = false;
+ }
+
/**
* @return True if this view supports insertion handles.
*/
@@ -2222,15 +2232,6 @@
mCorrectionHighlighter.highlight(info);
}
- void showSuggestions() {
- if (mSuggestionsPopupWindow == null) {
- mSuggestionsPopupWindow = new SuggestionsPopupWindow();
- }
- hideCursorAndSpanControllers();
- stopTextActionMode();
- mSuggestionsPopupWindow.show();
- }
-
void onScrollChanged() {
if (mPositionListener != null) {
mPositionListener.onScrollChanged();
@@ -2436,16 +2437,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()) {
@@ -2506,11 +2505,40 @@
.setEnabled(mTextView.canSelectAllText())
.setOnMenuItemClickListener(mOnContextMenuItemClickListener);
- mPreserveDetachedSelection = true;
+ mPreserveSelection = true;
}
- private void replaceWithSuggestion(SuggestionInfo suggestionInfo, int spanStart, int spanEnd) {
+ private void replaceWithSuggestion(final SuggestionInfo suggestionInfo) {
final Editable editable = (Editable) mTextView.getText();
+ if (editable.getSpanStart(suggestionInfo.mSuggestionSpan) < 0) {
+ // Suggestion span coundn't be found. Try to find a suggestion span that has the same
+ // contents.
+ final SuggestionSpan[] suggestionSpans = editable.getSpans(
+ suggestionInfo.mSuggestionSpanStart, suggestionInfo.mSuggestionSpanEnd,
+ SuggestionSpan.class);
+ for (final SuggestionSpan suggestionSpan : suggestionSpans) {
+ final int spanStart = editable.getSpanStart(suggestionSpan);
+ if (spanStart != suggestionInfo.mSuggestionSpanStart) {
+ continue;
+ }
+ int spanEnd = editable.getSpanEnd(suggestionSpan);
+ if (spanEnd != suggestionInfo.mSuggestionSpanEnd) {
+ continue;
+ }
+ if (suggestionSpan.equals(suggestionInfo.mSuggestionSpan)) {
+ // Found.
+ suggestionInfo.mSuggestionSpan = suggestionSpan;
+ break;
+ }
+ }
+ }
+ final int spanStart = editable.getSpanStart(suggestionInfo.mSuggestionSpan);
+ final int spanEnd = editable.getSpanEnd(suggestionInfo.mSuggestionSpan);
+ if (spanStart < 0 || spanEnd <= spanStart) {
+ // Span has been removed
+ return;
+ }
+
final String originalText = TextUtils.substring(editable, spanStart, spanEnd);
// SuggestionSpans are removed by replace: save them before
SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd,
@@ -2584,11 +2612,7 @@
clear();
return false;
}
- final Spannable spannable = (Spannable) mTextView.getText();
- final SuggestionSpan suggestionSpan =
- mSuggestionInfosInContextMenu[index].mSuggestionSpan;
- replaceWithSuggestion(mSuggestionInfosInContextMenu[index],
- spannable.getSpanStart(suggestionSpan), spannable.getSpanEnd(suggestionSpan));
+ replaceWithSuggestion(mSuggestionInfosInContextMenu[index]);
clear();
return true;
}
@@ -3019,13 +3043,19 @@
}
private static class SuggestionInfo {
- // Range of actual suggestion within text
+ // Range of actual suggestion within mText
int mSuggestionStart, mSuggestionEnd;
// The SuggestionSpan that this TextView represents
@Nullable
SuggestionSpan mSuggestionSpan;
+ // The SuggestionSpan start position
+ int mSuggestionSpanStart;
+
+ // The SuggestionSpan end position
+ int mSuggestionSpanEnd;
+
// The index of this suggestion inside suggestionSpan
int mSuggestionIndex;
@@ -3132,6 +3162,8 @@
suggestionInfo.mSuggestionIndex = suggestionIndex;
suggestionInfo.mSuggestionStart = 0;
suggestionInfo.mSuggestionEnd = suggestion.length();
+ suggestionInfo.mSuggestionSpanStart = spanStart;
+ suggestionInfo.mSuggestionSpanEnd = spanEnd;
suggestionInfo.mText.replace(0, suggestionInfo.mText.length(), suggestion);
numberOfSuggestions++;
if (numberOfSuggestions >= suggestionInfos.length) {
@@ -3160,6 +3192,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 +3210,7 @@
((Spannable) mTextView.getText()).removeSpan(mSuggestionRangeSpan);
mTextView.setCursorVisible(mCursorWasVisibleBeforeSuggestions);
- if (hasInsertionController()) {
+ if (hasInsertionController() && !extractedTextModeWillBeStarted()) {
getInsertionController().show();
}
}
@@ -3213,12 +3246,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 +3360,9 @@
@Override
public void show() {
if (!(mTextView.getText() instanceof Editable)) return;
+ if (extractedTextModeWillBeStarted()) {
+ return;
+ }
if (updateSuggestions()) {
mCursorWasVisibleBeforeSuggestions = mCursorVisible;
@@ -3374,12 +3410,13 @@
popupBackground.getPadding(mTempRect);
width += mTempRect.left + mTempRect.right;
}
+ mSuggestionListView.getLayoutParams().width = width;
mPopupWindow.setWidth(width);
}
@Override
protected int getTextOffset() {
- return mTextView.getSelectionStart();
+ return (mTextView.getSelectionStart() + mTextView.getSelectionStart()) / 2;
}
@Override
@@ -3420,10 +3457,8 @@
if ((suggestionSpan.getFlags() & SuggestionSpan.FLAG_MISSPELLED) != 0) {
mMisspelledSpan = suggestionSpan;
}
- final int spanStart = spannable.getSpanStart(suggestionSpan);
- final int spanEnd = spannable.getSpanEnd(suggestionSpan);
- spanUnionStart = Math.min(spanUnionStart, spanStart);
- spanUnionEnd = Math.max(spanUnionEnd, spanEnd);
+ spanUnionStart = Math.min(spanUnionStart, suggestionInfo.mSuggestionSpanStart);
+ spanUnionEnd = Math.max(spanUnionEnd, suggestionInfo.mSuggestionSpanEnd);
}
for (int i = 0; i < mNumberOfSuggestions; i++) {
@@ -3462,8 +3497,8 @@
private void highlightTextDifferences(SuggestionInfo suggestionInfo, int unionStart,
int unionEnd) {
final Spannable text = (Spannable) mTextView.getText();
- final int spanStart = text.getSpanStart(suggestionInfo.mSuggestionSpan);
- final int spanEnd = text.getSpanEnd(suggestionInfo.mSuggestionSpan);
+ final int spanStart = suggestionInfo.mSuggestionSpanStart;
+ final int spanEnd = suggestionInfo.mSuggestionSpanEnd;
// Adjust the start/end of the suggestion span
suggestionInfo.mSuggestionStart = spanStart - unionStart;
@@ -3481,17 +3516,8 @@
@Override
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) {
- // Span has been removed
- hideWithCleanUp();
- return;
- }
- replaceWithSuggestion(suggestionInfo, spanStart, spanEnd);
+ replaceWithSuggestion(suggestionInfo);
hideWithCleanUp();
}
}
@@ -3554,7 +3580,6 @@
}
if (menu.hasVisibleItems() || mode.getCustomView() != null) {
- mTextView.setHasTransientState(true);
return true;
} else {
return false;
@@ -3624,8 +3649,7 @@
}
private void updateReplaceItem(Menu menu) {
- boolean canReplace = mTextView.isSuggestionsEnabled() && shouldOfferToShowSuggestions()
- && !(mTextView.isInExtractedMode() && mTextView.hasSelection());
+ boolean canReplace = mTextView.isSuggestionsEnabled() && shouldOfferToShowSuggestions();
boolean replaceItemExists = menu.findItem(TextView.ID_REPLACE) != null;
if (canReplace && !replaceItemExists) {
menu.add(Menu.NONE, TextView.ID_REPLACE, MENU_ITEM_ORDER_REPLACE,
@@ -3655,15 +3679,14 @@
customCallback.onDestroyActionMode(mode);
}
- /*
- * If we're ending this mode because we're detaching from a window,
- * we still have selection state to preserve. Don't clear it, we'll
- * bring back the selection mode when (if) we get reattached.
- */
- if (!mPreserveDetachedSelection) {
+ if (!mPreserveSelection) {
+ /*
+ * Leave current selection when we tentatively destroy action mode for the
+ * selection. If we're detaching from a window, we'll bring back the selection
+ * mode when (if) we get reattached.
+ */
Selection.setSelection((Spannable) mTextView.getText(),
mTextView.getSelectionEnd());
- mTextView.setHasTransientState(false);
}
if (mSelectionModifierCursorController != null) {
@@ -4386,7 +4409,7 @@
if (distanceSquared < touchSlop * touchSlop) {
// Tapping on the handle toggles the insertion action mode.
if (mTextActionMode != null) {
- mTextActionMode.finish();
+ stopTextActionMode();
} else {
startInsertionActionMode();
}
@@ -4803,6 +4826,10 @@
* preventing the activity from being recycled.
*/
public void onDetached();
+
+ public boolean isCursorBeingModified();
+
+ public boolean isActive();
}
private class InsertionPointCursorController implements CursorController {
@@ -4846,6 +4873,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 +5072,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 +5146,7 @@
if (mInsertionActionModeRunnable != null) {
mTextView.removeCallbacks(mInsertionActionModeRunnable);
}
- if (mTextActionMode != null) {
- mTextActionMode.finish();
- }
+ stopTextActionMode();
if (!selectCurrentParagraph()) {
return false;
}
@@ -5222,6 +5255,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 +5270,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 +5297,11 @@
if (mStartHandle != null) mStartHandle.onDetached();
if (mEndHandle != null) mEndHandle.onDetached();
}
+
+ @Override
+ public boolean isActive() {
+ return mStartHandle != null && mStartHandle.isShowing();
+ }
}
private class CorrectionHighlighter {
@@ -5975,7 +6025,7 @@
private boolean fireIntent(Intent intent) {
if (intent != null && Intent.ACTION_PROCESS_TEXT.equals(intent.getAction())) {
intent.putExtra(Intent.EXTRA_PROCESS_TEXT, mTextView.getSelectedText());
- mEditor.mPreserveDetachedSelection = true;
+ mEditor.mPreserveSelection = true;
mTextView.startActivityForResult(intent, TextView.PROCESS_TEXT_REQUEST_CODE);
return true;
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index df2f575..dd6a41f 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1651,10 +1651,11 @@
// to executing this method, so we can rely on that instead.
final Transition exitTransition = mExitTransition;
if (mIsAnchorRootAttached && exitTransition != null && decorView.isLaidOut()) {
- // The decor view is non-interactive during exit transitions.
+ // The decor view is non-interactive and non-IME-focusable during exit transitions.
final LayoutParams p = (LayoutParams) decorView.getLayoutParams();
p.flags |= LayoutParams.FLAG_NOT_TOUCHABLE;
p.flags |= LayoutParams.FLAG_NOT_FOCUSABLE;
+ p.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM;
mWindowManager.updateViewLayout(decorView, p);
// Once we start dismissing the decor view, all state (including
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 2099b04..72a50ec1 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..ac3eaf7 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,16 @@
if (newSelEnd < 0) {
newSelEnd = Selection.getSelectionEnd(buf);
}
+
+ if (newSelStart == newSelEnd && hasTransientState()) {
+ setHasTransientState(false);
+ } else if (newSelStart != newSelEnd && !hasTransientState()) {
+ setHasTransientState(true);
+ }
+
+ if (mEditor != null) {
+ mEditor.refreshTextActionMode();
+ }
onSelectionChanged(newSelStart, newSelEnd);
}
}
@@ -8616,78 +8623,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 +9206,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 +9396,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 +9422,6 @@
case ID_CUT:
setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max)));
deleteText_internal(min, max);
- stopTextActionMode();
return true;
case ID_COPY:
@@ -9703,12 +9677,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 +9715,6 @@
}
}
}
- stopTextActionMode();
sLastCutCopyOrTextChangedTime = 0;
}
}
@@ -9760,7 +9727,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 +10045,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 +10058,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..ea62899 100644
--- a/core/java/com/android/internal/app/LocalePickerWithRegion.java
+++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java
@@ -21,6 +21,7 @@
import android.app.ListFragment;
import android.content.Context;
import android.os.Bundle;
+import android.text.TextUtils;
import android.util.LocaleList;
import android.view.Menu;
import android.view.MenuInflater;
@@ -50,7 +51,11 @@
private Set<LocaleStore.LocaleInfo> mLocaleList;
private LocaleStore.LocaleInfo mParentLocale;
private boolean mTranslatedOnly = false;
- private boolean mCountryMode = false;
+ private SearchView mSearchView = null;
+ private CharSequence mPreviousSearch = null;
+ private boolean mPreviousSearchHadFocus = false;
+ private int mFirstVisiblePosition = 0;
+ private int mTopDistance = 0;
/**
* Other classes can register to be notified when a locale was selected.
@@ -70,15 +75,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 +100,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 +113,7 @@
Collections.addAll(langTagsToIgnore, langTags);
}
- if (countryMode) {
+ if (parent != null) {
mLocaleList = LocaleStore.getLevelLocales(context,
langTagsToIgnore, parent, translatedOnly);
if (mLocaleList.size() <= 1) {
@@ -138,13 +135,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,25 +159,41 @@
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) {
+ getActivity().setTitle(mParentLocale.getFullNameNative());
} else {
- this.getActivity().setTitle(R.string.language_selection_title);
+ getActivity().setTitle(R.string.language_selection_title);
}
getListView().requestFocus();
}
@Override
+ public void onPause() {
+ super.onPause();
+
+ // Save search status
+ if (mSearchView != null) {
+ mPreviousSearchHadFocus = mSearchView.hasFocus();
+ mPreviousSearch = mSearchView.getQuery();
+ } else {
+ mPreviousSearchHadFocus = false;
+ mPreviousSearch = null;
+ }
+
+ // Save scroll position
+ final ListView list = getListView();
+ final View firstChild = list.getChildAt(0);
+ mFirstVisiblePosition = list.getFirstVisiblePosition();
+ mTopDistance = (firstChild == null) ? 0 : (firstChild.getTop() - list.getPaddingTop());
+ }
+
+ @Override
public void onListItemClick(ListView l, View v, int position, long id) {
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,15 +216,30 @@
@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);
- SearchView mSearchView = (SearchView) mSearchMenuItem.getActionView();
+ final MenuItem searchMenuItem = menu.findItem(R.id.locale_search_menu);
+ mSearchView = (SearchView) searchMenuItem.getActionView();
mSearchView.setQueryHint(getText(R.string.search_language_hint));
mSearchView.setOnQueryTextListener(this);
- mSearchView.setQuery("", false /* submit */);
+
+ // Restore previous search status
+ if (!TextUtils.isEmpty(mPreviousSearch)) {
+ searchMenuItem.expandActionView();
+ mSearchView.setIconified(false);
+ mSearchView.setActivated(true);
+ if (mPreviousSearchHadFocus) {
+ mSearchView.requestFocus();
+ }
+ mSearchView.setQuery(mPreviousSearch, true /* submit */);
+ } else {
+ mSearchView.setQuery(null, false /* submit */);
+ }
+
+ // Restore previous scroll position
+ getListView().setSelectionFromTop(mFirstVisiblePosition, mTopDistance);
}
}
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/inputmethod/LocaleUtils.java b/core/java/com/android/internal/inputmethod/LocaleUtils.java
index 99bb4cb..2aa660e 100644
--- a/core/java/com/android/internal/inputmethod/LocaleUtils.java
+++ b/core/java/com/android/internal/inputmethod/LocaleUtils.java
@@ -18,15 +18,17 @@
import com.android.internal.annotations.VisibleForTesting;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.text.TextUtils;
+import android.icu.util.ULocale;
import android.util.LocaleList;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
import java.util.Locale;
-import java.util.Objects;
public final class LocaleUtils {
@@ -36,12 +38,138 @@
Locale get(@Nullable T source);
}
- @Nullable
- private static String getLanguage(@Nullable Locale locale) {
- if (locale == null) {
- return null;
+ /**
+ * Calculates a matching score for the single desired locale.
+ *
+ * @see LocaleUtils#calculateMatchingScore(ULocale, LocaleList, byte[])
+ *
+ * @param supported The locale supported by IME subtype.
+ * @param desired The locale preferred by user.
+ * @return A score based on the locale matching for the default subtype enabling.
+ */
+ @IntRange(from=1, to=3)
+ private static byte calculateMatchingSubScore(@NonNull final ULocale supported,
+ @NonNull final ULocale desired) {
+ // Assuming supported/desired is fully expanded.
+ if (supported.equals(desired)) {
+ return 3; // Exact match.
}
- return locale.getLanguage();
+
+ // Skip language matching since it was already done in calculateMatchingScore.
+
+ final String supportedScript = supported.getScript();
+ if (supportedScript.isEmpty() || !supportedScript.equals(desired.getScript())) {
+ // TODO: Need subscript matching. For example, Hanb should match with Bopo.
+ return 1;
+ }
+
+ final String supportedCountry = supported.getCountry();
+ if (supportedCountry.isEmpty() || !supportedCountry.equals(desired.getCountry())) {
+ return 2;
+ }
+
+ // Ignore others e.g. variants, extensions.
+ return 3;
+ }
+
+ /**
+ * Calculates a matching score for the desired locale list.
+ *
+ * <p>The supported locale gets a matching score of 3 if all language, script and country of the
+ * supported locale matches with the desired locale. The supported locale gets a matching
+ * score of 2 if the language and script of the supported locale matches with the desired
+ * locale. The supported locale gets a matching score of 1 if only language of the supported
+ * locale matches with the desired locale. The supported locale gets a matching score of 0 if
+ * the language of the supported locale doesn't match with the desired locale.</p>
+ *
+ * @param supported The locale supported by IME subtyle.
+ * @param desired The locale list preferred by user. Typically system locale list.
+ * @param out The output buffer to be stored the individual score for the desired language list.
+ * The length of {@code out} must be same as the length of {@code desired} language list.
+ * @return {@code false} if supported locale doesn't match with any desired locale list.
+ * Otherwise {@code true}.
+ */
+ private static boolean calculateMatchingScore(@NonNull final ULocale supported,
+ @NonNull final LocaleList desired, @NonNull byte[] out) {
+ if (desired.isEmpty()) {
+ return false;
+ }
+
+ boolean allZeros = true;
+ final int N = desired.size();
+ for (int i = 0; i < N; ++i) {
+ final Locale locale = desired.get(i);
+
+ if (!locale.getLanguage().equals(supported.getLanguage())) {
+ // TODO: cache the result of addLikelySubtags if it is slow.
+ out[i] = 0;
+ } else {
+ out[i] = calculateMatchingSubScore(
+ supported, ULocale.addLikelySubtags(ULocale.forLocale(locale)));
+ if (allZeros && out[i] != 0) {
+ allZeros = false;
+ }
+ }
+ }
+ return !allZeros;
+ }
+
+ private static final class ScoreEntry implements Comparable<ScoreEntry> {
+ public int mIndex = -1;
+ @NonNull public final byte[] mScore; // matching score of the i-th system languages.
+
+ ScoreEntry(@NonNull byte[] score, int index) {
+ mScore = new byte[score.length];
+ set(score, index);
+ }
+
+ private void set(@NonNull byte[] score, int index) {
+ for (int i = 0; i < mScore.length; ++i) {
+ mScore[i] = score[i];
+ }
+ mIndex = index;
+ }
+
+ /**
+ * Update score and index if the given score is better than this.
+ */
+ public void updateIfBetter(@NonNull byte[] score, int index) {
+ if (compare(mScore, score) == -1) { // mScore < score
+ set(score, index);
+ }
+ }
+
+ /**
+ * Provides comaprison for bytes[].
+ *
+ * <p> Comparison does as follows. If the first value of {@code left} is larger than the
+ * first value of {@code right}, {@code left} is large than {@code right}. If the first
+ * value of {@code left} is less than the first value of {@code right}, {@code left} is less
+ * than {@code right}. If the first value of {@code left} and the first value of
+ * {@code right} is equal, do the same comparison to the next value. Finally if all values
+ * in {@code left} and {@code right} are equal, {@code left} and {@code right} is equal.</p>
+ *
+ * @param left The length must be equal to {@code right}.
+ * @param right The length must be equal to {@code left}.
+ * @return 1 if {@code left} is larger than {@code right}. -1 if {@code left} is less than
+ * {@code right}. 0 if {@code left} and {@code right} is equal.
+ */
+ @IntRange(from=-1, to=1)
+ private static int compare(@NonNull byte[] left, @NonNull byte[] right) {
+ for (int i = 0; i < left.length; ++i) {
+ if (left[i] > right[i]) {
+ return 1;
+ } else if (left[i] < right[i]) {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public int compareTo(final ScoreEntry other) {
+ return -1 * compare(mScore, other.mScore); // Order by descending order.
+ }
}
/**
@@ -52,14 +180,8 @@
* {@code "en-GB", "ja", "en-AU", "fr-CA", "en-IN"} is specified to {@code preferredLanguages},
* this method tries to copy at most one English locale, at most one Japanese, and at most one
* French locale from {@code source} to {@code dest}. Here the best matching English locale
- * will be searched from {@code source} as follows.
- * <ol>
- * <li>The first instance in {@code sources} that exactly matches {@code "en-GB"}</li>
- * <li>The first instance in {@code sources} that exactly matches {@code "en-AU"}</li>
- * <li>The first instance in {@code sources} that exactly matches {@code "en-IN"}</li>
- * <li>The first instance in {@code sources} that partially matches {@code "en"}</li>
- * </ol>
- * <p>Then this method iterates the same algorithm for Japanese then French.</p>
+ * will be searched from {@code source} based on matching score. For the score design, see
+ * {@link LocaleUtils#calculateMatchingScore(ULocale, LocaleList, byte[])}</p>
*
* @param sources Source items to be filtered.
* @param extractor Type converter from the source items to {@link Locale} object.
@@ -74,69 +196,31 @@
@NonNull LocaleExtractor<T> extractor,
@NonNull LocaleList preferredLanguages,
@NonNull ArrayList<T> dest) {
- final Locale[] availableLocales = new Locale[sources.size()];
- for (int i = 0; i < availableLocales.length; ++i) {
- availableLocales[i] = extractor.get(sources.get(i));
- }
- final Locale[] sortedPreferredLanguages = new Locale[preferredLanguages.size()];
- if (sortedPreferredLanguages.length > 0) {
- int nextIndex = 0;
- final int N = preferredLanguages.size();
- languageLoop:
- for (int i = 0; i < N; ++i) {
- final String language = getLanguage(preferredLanguages.get(i));
- for (int j = 0; j < nextIndex; ++j) {
- if (TextUtils.equals(getLanguage(sortedPreferredLanguages[j]), language)) {
- continue languageLoop;
- }
- }
- for (int j = i; j < N; ++j) {
- final Locale locale = preferredLanguages.get(j);
- if (TextUtils.equals(language, getLanguage(locale))) {
- sortedPreferredLanguages[nextIndex] = locale;
- ++nextIndex;
- }
- }
+ final HashMap<String, ScoreEntry> scoreboard = new HashMap<>();
+ final byte[] score = new byte[preferredLanguages.size()];
+
+ final int sourceSize = sources.size();
+ for (int i = 0; i < sourceSize; ++i) {
+ final Locale locale = extractor.get(sources.get(i));
+ if (locale == null ||
+ !calculateMatchingScore(ULocale.addLikelySubtags(ULocale.forLocale(locale)),
+ preferredLanguages, score)) {
+ continue;
+ }
+
+ final String lang = locale.getLanguage();
+ final ScoreEntry bestScore = scoreboard.get(lang);
+ if (bestScore == null) {
+ scoreboard.put(lang, new ScoreEntry(score, i));
+ } else {
+ bestScore.updateIfBetter(score, i);
}
}
-
- for (int languageIndex = 0; languageIndex < sortedPreferredLanguages.length;) {
- // Finding the range.
- final String language = getLanguage(sortedPreferredLanguages[languageIndex]);
- int nextLanguageIndex = languageIndex;
- for (; nextLanguageIndex < sortedPreferredLanguages.length; ++nextLanguageIndex) {
- final Locale locale = sortedPreferredLanguages[nextLanguageIndex];
- if (!TextUtils.equals(getLanguage(locale), language)) {
- break;
- }
- }
-
- // Check exact match
- boolean found = false;
- for (int i = languageIndex; !found && i < nextLanguageIndex; ++i) {
- final Locale locale = sortedPreferredLanguages[i];
- for (int j = 0; j < availableLocales.length; ++j) {
- if (!Objects.equals(locale, availableLocales[j])) {
- continue;
- }
- dest.add(sources.get(j));
- found = true;
- break;
- }
- }
-
- if (!found) {
- // No exact match. Use language match.
- for (int j = 0; j < availableLocales.length; ++j) {
- if (!TextUtils.equals(language, getLanguage(availableLocales[j]))) {
- continue;
- }
- dest.add(sources.get(j));
- break;
- }
- }
- languageIndex = nextLanguageIndex;
+ final ScoreEntry[] result = scoreboard.values().toArray(new ScoreEntry[scoreboard.size()]);
+ Arrays.sort(result);
+ for (final ScoreEntry entry : result) {
+ dest.add(sources.get(entry.mIndex));
}
}
-}
\ No newline at end of file
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index f178c8c..1b52146 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -754,8 +754,7 @@
try {
ParcelFileDescriptor pfd = service.getStatisticsStream();
if (pfd != null) {
- FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
- try {
+ try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
byte[] data = readFully(fis, MemoryFile.getSize(pfd.getFileDescriptor()));
Parcel parcel = Parcel.obtain();
parcel.unmarshall(data, 0, data.length);
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/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 8026949..a84a061 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -27,6 +27,7 @@
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
/**
@@ -126,6 +127,13 @@
/**
* Checks if given array is null or has zero elements.
*/
+ public static boolean isEmpty(@Nullable List<?> array) {
+ return array == null || array.isEmpty();
+ }
+
+ /**
+ * Checks if given array is null or has zero elements.
+ */
public static <T> boolean isEmpty(@Nullable T[] array) {
return array == null || array.length == 0;
}
diff --git a/core/java/com/android/internal/util/WakeupMessage.java b/core/java/com/android/internal/util/WakeupMessage.java
index 451078b..2653745 100644
--- a/core/java/com/android/internal/util/WakeupMessage.java
+++ b/core/java/com/android/internal/util/WakeupMessage.java
@@ -21,7 +21,9 @@
import android.os.Handler;
import android.os.Message;
-/**
+import com.android.internal.annotations.VisibleForTesting;
+
+ /**
* An AlarmListener that sends the specified message to a Handler and keeps the system awake until
* the message is processed.
*
@@ -36,9 +38,13 @@
*/
public class WakeupMessage implements AlarmManager.OnAlarmListener {
private final AlarmManager mAlarmManager;
- private final Handler mHandler;
- private final String mCmdName;
- private final int mCmd, mArg1, mArg2;
+
+ @VisibleForTesting
+ protected final Handler mHandler;
+ @VisibleForTesting
+ protected final String mCmdName;
+ @VisibleForTesting
+ protected final int mCmd, mArg1, mArg2;
private boolean mScheduled;
public WakeupMessage(Context context, Handler handler,
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/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
index 6bba1b3..f63afad 100644
--- a/core/java/com/android/internal/widget/MediaNotificationView.java
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -89,36 +89,50 @@
int topMargin = getMeasuredHeight() - mRightIcon.getMeasuredHeight()
- iconParams.bottomMargin;
// If the topMargin is high enough we can also remove the header constraint!
+ boolean reMeasure = false;
if (!hasIcon || topMargin >= mImageMinTopMargin) {
- resetHeaderIndention();
+ reMeasure = resetHeaderIndention();
} else {
int paddingEnd = mNotificationContentImageMarginEnd;
ViewGroup.MarginLayoutParams headerParams =
(MarginLayoutParams) mHeader.getLayoutParams();
- headerParams.setMarginEnd(mRightIcon.getMeasuredWidth() + iconParams.getMarginEnd());
- if (mHeader.getPaddingEnd() != paddingEnd) {
- mHeader.setPadding(
- isLayoutRtl() ? paddingEnd : mHeader.getPaddingLeft(),
- mHeader.getPaddingTop(),
- isLayoutRtl() ? mHeader.getPaddingLeft() : paddingEnd,
- mHeader.getPaddingBottom());
+ int newMarginEnd = mRightIcon.getMeasuredWidth() + iconParams.getMarginEnd();
+ if (headerParams.getMarginEnd() != newMarginEnd) {
+ headerParams.setMarginEnd(newMarginEnd);
mHeader.setLayoutParams(headerParams);
+ reMeasure = true;
}
+ if (mHeader.getPaddingEnd() != paddingEnd) {
+ mHeader.setPaddingRelative(mHeader.getPaddingStart(),
+ mHeader.getPaddingTop(),
+ paddingEnd,
+ mHeader.getPaddingBottom());
+ reMeasure = true;
+ }
+ }
+ if (reMeasure) {
+ measureChildWithMargins(mHeader, widthMeasureSpec, 0, heightMeasureSpec, 0);
}
}
- private void resetHeaderIndention() {
+ private boolean resetHeaderIndention() {
+ boolean remeasure = false;
if (mHeader.getPaddingEnd() != mNotificationContentMarginEnd) {
- ViewGroup.MarginLayoutParams headerParams =
- (MarginLayoutParams) mHeader.getLayoutParams();
- headerParams.setMarginEnd(0);
- mHeader.setPadding(
- isLayoutRtl() ? mNotificationContentMarginEnd : mHeader.getPaddingLeft(),
+ mHeader.setPaddingRelative(mHeader.getPaddingStart(),
mHeader.getPaddingTop(),
- isLayoutRtl() ? mHeader.getPaddingLeft() : mNotificationContentMarginEnd,
+ mNotificationContentMarginEnd,
mHeader.getPaddingBottom());
- mHeader.setLayoutParams(headerParams);
+ remeasure = true;
}
+ ViewGroup.MarginLayoutParams headerParams =
+ (MarginLayoutParams) mHeader.getLayoutParams();
+ headerParams.setMarginEnd(0);
+ if (headerParams.getMarginEnd() != 0) {
+ headerParams.setMarginEnd(0);
+ mHeader.setLayoutParams(headerParams);
+ remeasure = true;
+ }
+ return remeasure;
}
public MediaNotificationView(Context context, AttributeSet attrs, int defStyleAttr,
diff --git a/core/java/com/android/server/net/NetworkPinner.java b/core/java/com/android/server/net/NetworkPinner.java
new file mode 100644
index 0000000..d922a48
--- /dev/null
+++ b/core/java/com/android/server/net/NetworkPinner.java
@@ -0,0 +1,146 @@
+/*
+ * 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.net;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.net.NetworkRequest;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * A class that pins a process to the first network that satisfies a particular NetworkRequest.
+ *
+ * We use this to maintain compatibility with pre-M apps that call WifiManager.enableNetwork()
+ * to connect to a Wi-Fi network that has no Internet access, and then assume that they will be
+ * able to use that network because it's the system default.
+ *
+ * In order to maintain compatibility with apps that call setProcessDefaultNetwork themselves,
+ * we try not to set the default network unless they have already done so, and we try not to
+ * clear the default network unless we set it ourselves.
+ *
+ * This should maintain behaviour that's compatible with L, which would pin the whole system to
+ * any wifi network that was created via enableNetwork(..., true) until that network
+ * disconnected.
+ *
+ * Note that while this hack allows network traffic to flow, it is quite limited. For example:
+ *
+ * 1. setProcessDefaultNetwork only affects this process, so:
+ * - Any subprocesses spawned by this process will not be pinned to Wi-Fi.
+ * - If this app relies on any other apps on the device also being on Wi-Fi, that won't work
+ * either, because other apps on the device will not be pinned.
+ * 2. The behaviour of other APIs is not modified. For example:
+ * - getActiveNetworkInfo will return the system default network, not Wi-Fi.
+ * - There will be no CONNECTIVITY_ACTION broadcasts about TYPE_WIFI.
+ * - getProcessDefaultNetwork will not return null, so if any apps are relying on that, they
+ * will be surprised as well.
+ *
+ * This class is a per-process singleton because the process default network is a per-process
+ * singleton.
+ *
+ */
+public class NetworkPinner extends NetworkCallback {
+
+ private static final String TAG = NetworkPinner.class.getSimpleName();
+
+ @VisibleForTesting
+ protected static final Object sLock = new Object();
+
+ @GuardedBy("sLock")
+ private static ConnectivityManager sCM;
+ @GuardedBy("sLock")
+ private static Callback sCallback;
+ @VisibleForTesting
+ @GuardedBy("sLock")
+ protected static Network sNetwork;
+
+ private static void maybeInitConnectivityManager(Context context) {
+ // TODO: what happens if an app calls a WifiManager API before ConnectivityManager is
+ // registered? Can we fix this by starting ConnectivityService before WifiService?
+ if (sCM == null) {
+ // Getting a ConnectivityManager does not leak the calling context, because it stores
+ // the application context and not the calling context.
+ sCM = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (sCM == null) {
+ throw new IllegalStateException("Bad luck, ConnectivityService not started.");
+ }
+ }
+ }
+
+ private static class Callback extends NetworkCallback {
+ @Override
+ public void onAvailable(Network network) {
+ synchronized(sLock) {
+ if (this != sCallback) return;
+
+ if (sCM.getBoundNetworkForProcess() == null && sNetwork == null) {
+ sCM.bindProcessToNetwork(network);
+ sNetwork = network;
+ Log.d(TAG, "Wifi alternate reality enabled on network " + network);
+ }
+ sLock.notify();
+ }
+ }
+
+ @Override
+ public void onLost(Network network) {
+ synchronized (sLock) {
+ if (this != sCallback) return;
+
+ if (network.equals(sNetwork) && network.equals(sCM.getBoundNetworkForProcess())) {
+ unpin();
+ Log.d(TAG, "Wifi alternate reality disabled on network " + network);
+ }
+ sLock.notify();
+ }
+ }
+ }
+
+ public static void pin(Context context, NetworkRequest request) {
+ synchronized (sLock) {
+ if (sCallback == null) {
+ maybeInitConnectivityManager(context);
+ sCallback = new Callback();
+ try {
+ sCM.registerNetworkCallback(request, sCallback);
+ } catch (SecurityException e) {
+ Log.d(TAG, "Failed to register network callback", e);
+ sCallback = null;
+ }
+ }
+ }
+ }
+
+ public static void unpin() {
+ synchronized (sLock) {
+ if (sCallback != null) {
+ try {
+ sCM.bindProcessToNetwork(null);
+ sCM.unregisterNetworkCallback(sCallback);
+ } catch (SecurityException e) {
+ Log.d(TAG, "Failed to unregister network callback", e);
+ }
+ sCallback = null;
+ sNetwork = null;
+ }
+ }
+ }
+}
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/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index 7a13fe4..5d496e5 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -94,8 +94,6 @@
SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight,
&(page->mContentRect));
- canvas->clipRect(page->mContentRect);
- canvas->translate(page->mContentRect.left(), page->mContentRect.top());
canvas->drawPicture(page->mPicture);
document->endPage();
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_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 660cbdc..302cf63 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -541,7 +541,6 @@
return;
}
//ALOGV("deleting lpTrack: %x\n", (int)lpTrack);
- lpTrack->stop();
// delete the JNI data
AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
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_opengl_GLES31.cpp b/core/jni/android_opengl_GLES31.cpp
index 5751add..156e7bd 100644
--- a/core/jni/android_opengl_GLES31.cpp
+++ b/core/jni/android_opengl_GLES31.cpp
@@ -888,9 +888,69 @@
static jint
android_glCreateShaderProgramv
(JNIEnv *_env, jobject _this, jint type, jobjectArray strings) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ GLsizei _count;
+ const GLchar** _strings = NULL;
+ jstring* _jstrings = NULL;
+ GLuint _returnValue = 0;
- jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
- return 0;
+ if (!strings) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "strings == null";
+ goto exit;
+ }
+
+ _count = _env->GetArrayLength(strings);
+
+ _strings = (const GLchar**) calloc(_count, sizeof(const GLchar*));
+ if (!_strings) {
+ _exception = 1;
+ _exceptionType = "java/lang/OutOfMemoryError";
+ _exceptionMessage = "out of memory";
+ goto exit;
+ }
+
+ _jstrings = (jstring*) calloc(_count, sizeof(jstring));
+ if (!_jstrings) {
+ _exception = 1;
+ _exceptionType = "java/lang/OutOfMemoryError";
+ _exceptionMessage = "out of memory";
+ goto exit;
+ }
+
+ for(int i = 0; i < _count; i++) {
+ _jstrings[i] = (jstring) _env->GetObjectArrayElement(strings, i);
+ if (!_jstrings[i]) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "strings == null";
+ goto exit;
+ }
+ _strings[i] = _env->GetStringUTFChars(_jstrings[i], 0);
+ }
+
+ _returnValue = glCreateShaderProgramv((GLenum)type, _count, _strings);
+exit:
+ if (_strings && _jstrings) {
+ for(int i = 0; i < _count; i++) {
+ if (_strings[i] && _jstrings[i]) {
+ _env->ReleaseStringUTFChars(_jstrings[i], _strings[i]);
+ }
+ }
+ }
+ if (_strings) {
+ free(_strings);
+ }
+ if (_jstrings) {
+ free(_jstrings);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+ return (jint)_returnValue;
}
/* void glBindProgramPipeline ( GLuint pipeline ) */
static void
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..fbc96c2 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" />
@@ -167,7 +168,7 @@
android:name="android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED" />
- <protected-broadcast
+ <protected-broadcast
android:name="android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_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 -->
<!-- ====================================================================== -->
@@ -976,6 +984,11 @@
<permission android:name="android.permission.SEND_RESPOND_VIA_MESSAGE"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application to send SMS to premium shortcodes without user permission.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.SEND_SMS_NO_CONFIRMATION"
+ android:protectionLevel="signature|privileged" />
+
<!-- Allows an application to filter carrier specific sms.
@hide -->
<permission android:name="android.permission.CARRIER_FILTER_SMS"
@@ -2761,12 +2774,11 @@
android:protectionLevel="signature" />
<!-- Must be required by an {@link
- android.service.notification.NotificationAssistantService},
- to ensure that only the system can bind to it.
+ android.service.notification.NotificationRankerService to ensure that only the system can bind to it.
<p>Protection level: signature
@hide This is not a third-party API (intended for system apps). -->
-->
- <permission android:name="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE"
+ <permission android:name="android.permission.BIND_NOTIFICATION_RANKER_SERVICE"
android:protectionLevel="signature" />
<!-- Must be required by a {@link
@@ -2921,6 +2933,12 @@
<permission android:name="android.permission.WRITE_BLOCKED_NUMBERS"
android:protectionLevel="signature" />
+ <!-- Must be required by an {@link android.service.vr.VrListenerService}, to ensure that only
+ the system can bind to it.
+ <p>Protection level: signature -->
+ <permission android:name="android.permission.BIND_VR_LISTENER_SERVICE"
+ android:protectionLevel="signature" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
diff --git a/core/res/assets/images/clock64.png b/core/res/assets/images/clock64.png
new file mode 100644
index 0000000..493a1ea
--- /dev/null
+++ b/core/res/assets/images/clock64.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/default_wallpaper.jpg b/core/res/res/drawable-nodpi/default_wallpaper.jpg
deleted file mode 100644
index d7475b4c..0000000
--- a/core/res/res/drawable-nodpi/default_wallpaper.jpg
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/default_wallpaper.png b/core/res/res/drawable-nodpi/default_wallpaper.png
new file mode 100644
index 0000000..e9c4d5c
--- /dev/null
+++ b/core/res/res/drawable-nodpi/default_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.jpg b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.jpg
deleted file mode 100644
index 03a14c0..0000000
--- a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.jpg
+++ /dev/null
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
new file mode 100644
index 0000000..9f3efa5
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.jpg b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.jpg
deleted file mode 100644
index 543d118..0000000
--- a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.jpg
+++ /dev/null
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
new file mode 100644
index 0000000..8199e70
--- /dev/null
+++ b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable/work_widget_mask_view_background.xml b/core/res/res/drawable/work_widget_mask_view_background.xml
deleted file mode 100644
index 17f0dbc..0000000
--- a/core/res/res/drawable/work_widget_mask_view_background.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-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.
--->
- <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
- <padding android:left="5dp" android:right="5dp" android:top="5dp" android:bottom="5dp"/>
- <stroke android:width="1dp" android:color="#CCCCCC" />
- </shape>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 6669bae..b8b00bf 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -33,16 +33,6 @@
android:layout_marginEnd="3dp"
/>
<TextView
- android:id="@+id/number_of_children"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:layout_marginEnd="3dp"
- android:layout_marginStart="2dp"
- android:visibility="gone"
- android:singleLine="true"
- />
- <TextView
android:id="@+id/app_name_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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/layout/work_widget_mask_view.xml b/core/res/res/layout/work_widget_mask_view.xml
index ce86ddc..3c47705 100644
--- a/core/res/res/layout/work_widget_mask_view.xml
+++ b/core/res/res/layout/work_widget_mask_view.xml
@@ -15,20 +15,24 @@
limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/work_widget_mask_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="#F3374248" >
+ android:background="#F3374248"
+ android:clickable="true" >
<ImageView android:id="@+id/work_widget_app_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"/>
+ android:layout_gravity="center"
+ android:clickable="false" />
- <ImageView
+ <ImageView android:id="@+id/work_widget_badge_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_marginBottom="4dp"
android:layout_marginRight="4dp"
- android:src="@drawable/ic_corp_badge_off" />
+ android:src="@drawable/ic_corp_badge_off"
+ android:clickable="false" />
</FrameLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 06fcda9..10cdae8 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Raak vir meer opsies."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-ontfouter gekoppel"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Raak om USB-ontfouting te deaktiveer."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Deel foutverslag?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deel tans foutverslag …"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Jou IT-administrateur het \'n foutverslag versoek om met die foutsporing van hierdie toestel te help. Programme en data sal dalk gedeel word en jou toestel sal dalk tydelik stadiger wees."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Jou IT-administrateur het \'n foutverslag versoek om met die foutsporing van hierdie toestel te help. Programme en data sal dalk gedeel word."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Dit sal jou toestel dalk tydelik stadiger maak"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"AANVAAR"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"WEIER"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Verander sleutelbord"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Kies sleutelborde"</string>
<string name="show_ime" msgid="2506087537466597099">"Hou dit op die skerm terwyl fisieke sleutelbord aktief is"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index f06d7de..1fb3c51 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ለተጨማሪ አማራጮች ነካ ያድርጉ።"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB አድስ ተያይዟል"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ማረሚያ ላለማንቃት ዳስስ።"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"የሳንካ ሪፖርት ይጋራ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"የሳንካ ሪፖርትን በማጋራት ላይ…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"የእርስዎ አይቲ አስተዳዳሪ ለዚህ መሣሪያ መላ ለመፈለግ እንዲያግዝ የሳንካ ሪፖርት ጠይቀዋል። መተግበሪያዎች እና ውሂብ ሊጋሩ ይችላሉ። ይሄ መሣሪያዎን ለጊዜው ሊያዘገየው ይችላል።"</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"የእርስዎ አይቲ አስተዳዳሪ ለዚህ መሣሪያ መላ ለመፈለግ የሳንካ ሪፖርት ጠይቀዋል። መተግበሪያዎች እና ውሂብ ሊጋሩ ይችላሉ።"</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"ይሄ መሣሪያዎን ለጊዜው ሊያዘገየው ይችላል"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ተቀበል"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ውድቅ አድርግ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"ቁልፍ ሰሌዳ ይቀይሩ"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"ቁልፍ ሰሌዳዎችን ምረጥ"</string>
<string name="show_ime" msgid="2506087537466597099">"አካላዊ የቁልፍ ሰሌዳ ገቢር ሆኖ ሳለ በማያ ገጽ ላይ አቆየው"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index d8a8377..518edab 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1084,13 +1084,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"المس للحصول على مزيد من الخيارات."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"تم توصيل تصحيح أخطاء USB"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"المس لتعطيل تصحيح أخطاء USB."</string>
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"جارٍ الحصول على تقرير الخطأ…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"هل تريد مشاركة تقرير الخطأ؟"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"جارٍ مشاركة تقرير الخطأ…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"طلب مشرف تكنولوجيا المعلومات الحصول على تقرير خطأ للمساعدة في تحرِّي مشكلة هذا الجهاز وإصلاحها. قد تتم مشاركة التطبيقات والبيانات. وقد يؤدي هذا إلى حدوث بطء مؤقت في جهازك."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"طلب مشرف تكنولوجيا المعلومات الحصول على تقرير خطأ للمساعدة في تحرِّي مشكلة هذا الجهاز وإصلاحها. قد تتم مشاركة التطبيقات والبيانات."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"قد يؤدي هذا إلى حدوث بطء مؤقت في جهازك"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"قبول"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"رفض"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"طلب مشرف تكنولوجيا المعلومات الحصول على تقرير خطأ للمساعدة في تحرِّي مشكلة هذا الجهاز وإصلاحها؛ ويمكن أن تتم مشاركة التطبيقات والبيانات."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"مشاركة"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"رفض"</string>
<string name="select_input_method" msgid="8547250819326693584">"تغيير لوحة المفاتيح"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"اختيار لوحات المفاتيح"</string>
<string name="show_ime" msgid="2506087537466597099">"استمرار عرضها على الشاشة أثناء نشاط لوحة المفاتيح الفعلية"</string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 33d1616..d155182 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Əlavə seçimlər üçün toxunun."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB sazlama qoşuludur"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB debaqı deaktivasiya etmək üçün toxunun."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Baq hesabatı paylaşılsın?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Baq hesabatı paylaşılır..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IT admininiz bu cihazda nasazlıqların aşkarlanması üçün baq hesabatı sorğusu göndərdi. Tətbiqlər və data paylaşıla və cihazınız surəti müvəqqəti azala bilər."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IT admininiz bu cihazda nasazlıqların aşkarlanması üçün baq hesabatı sorğusu göndərdi. Tətbiqlər və data paylaşıla bilər."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Bu cihazınızın sürətini müvəqqəti olaraq azalda bilər"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"QƏBUL EDİN"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RƏDD ET"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Klaviaturanı dəyişin"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Klaviaturaları seçin"</string>
<string name="show_ime" msgid="2506087537466597099">"Fiziki klaviatura aktiv olduğu halda ekranda saxlayın"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 8c00151..12ae1b0 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -163,7 +163,7 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Previše <xliff:g id="CONTENT_TYPE">%s</xliff:g> izbrisanih stavki."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Memorija tableta je puna! Izbrišite neke datoteke da biste oslobodili prostor."</string>
<string name="low_memory" product="watch" msgid="4415914910770005166">"Memorija sata je puna. Izbrišite neke datoteke da biste oslobodili prostor."</string>
- <string name="low_memory" product="tv" msgid="516619861191025923">"Skladišni prostor na TV-u je popunjen. Izbrišite neke datoteke da biste oslobodili prostor."</string>
+ <string name="low_memory" product="tv" msgid="516619861191025923">"Memorijski prostor na TV-u je popunjen. Izbrišite neke datoteke da biste oslobodili prostor."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Skladište telefona je puno! Izbrišite neke datoteke kako biste oslobodili prostor."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mreža se možda nadgleda"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Od strane nepoznate treće strane"</string>
@@ -312,7 +312,7 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Dozvoljava aplikaciji da učini sopstvene komponente trajnim u memoriji. Ovo može da ograniči memoriju dostupnu drugim aplikacijama i uspori tablet."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Dozvoljava aplikaciji da neke svoje delove trajno zadrži u memoriji. To može da ograniči memoriju dostupnu drugim aplikacijama i uspori TV."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Dozvoljava aplikaciji da učini sopstvene komponente trajnim u memoriji. Ovo može da ograniči memoriju dostupnu drugim aplikacijama i uspori telefon."</string>
- <string name="permlab_getPackageSize" msgid="7472921768357981986">"merenje prostora za skladištenje u aplikaciji"</string>
+ <string name="permlab_getPackageSize" msgid="7472921768357981986">"merenje memorijskog prostora u aplikaciji"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Dozvoljava aplikaciji da preuzme veličine kôda, podataka i keša."</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"izmena podešavanja sistema"</string>
<string name="permdesc_writeSettings" msgid="7775723441558907181">"Dozvoljava aplikaciji da menja podatke o podešavanju sistema. Zlonamerne aplikacije mogu da oštete konfiguraciju sistema."</string>
@@ -885,9 +885,9 @@
<string name="deleteText" msgid="6979668428458199034">"Izbriši"</string>
<string name="inputMethod" msgid="1653630062304567879">"Metod unosa"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Radnje u vezi sa tekstom"</string>
- <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Prostor za skladištenje je na izmaku"</string>
+ <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Memorijski prostor je na izmaku"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke sistemske funkcije možda ne funkcionišu"</string>
- <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno skladišnog prostora za sistem. Uverite se da imate 250 MB slobodnog prostora i ponovo pokrenite."</string>
+ <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno memorijskog prostora za sistem. Uverite se da imate 250 MB slobodnog prostora i ponovo pokrenite."</string>
<string name="app_running_notification_title" msgid="8718335121060787914">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je pokrenuta"</string>
<string name="app_running_notification_text" msgid="4653586947747330058">"Dodirnite za više informacija ili zaustavljanje aplikacije."</string>
<string name="ok" msgid="5970060430562524910">"Potvrdi"</string>
@@ -1060,13 +1060,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Dodirnite za još opcija."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Otklanjanje grešaka sa USB-a je uspostavljeno"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dodirnite da biste onemogućili otklanjanje grešaka sa USB-a."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Želite li da podelite izveštaj o grešci?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deli se izveštaj o grešci…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IT administrator je zatražio izveštaj o grešci radi lakšeg rešavanja problema u vezi sa ovim uređajem. Aplikacije i podaci mogu da se dele, a uređaj će se privremeno usporiti."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IT administrator je zatražio izveštaj o grešci radi lakšeg rešavanja problema u vezi sa ovim uređajem. Aplikacije i podaci mogu da se dele."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Ovo će privremeno usporiti uređaj"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRIHVATI"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODBIJ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Promenite tastaturu"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Izaberite tastature"</string>
<string name="show_ime" msgid="2506087537466597099">"Zadrži ga na ekranu dok je fizička tastatura aktivna"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index ac2a0ec..9cdd298 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Докоснете за още опции."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Отстраняване на грешки през USB"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Докоснете за деактивиране"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Да се сподели ли сигналът за програмна грешка?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Сигналът за програмна грешка се споделя…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Системният ви администратор поиска сигнал за програмна грешка с цел отстраняване на неизправностите на устройството. Възможно е да бъдат споделени приложения и данни и работата на устройството ви временно да се забави."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Системният ви администратор поиска сигнал за програмна грешка с цел отстраняване на неизправностите на това устройство. Възможно е да бъдат споделени приложения и данни."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Това може временно да забави работата на устройството ви"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИЕМАМ"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ОТХВЪРЛЯМ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Промяна на клавиатурата"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Избиране на клавиатури"</string>
<string name="show_ime" msgid="2506087537466597099">"Показване на екрана, докато физическата клавиатура е активна"</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 4e6cd4b..a598d3b 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"আরো বিকল্পের জন্য স্পর্শ করুন৷"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ডিবাগিং সংযুক্ত হয়েছে"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ডিবাগিং অক্ষম করতে স্পর্শ করুন৷"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ত্রুটির প্রতিবেদন শেয়ার করবেন?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ত্রুটির প্রতিবেদন শেয়ার করা হচ্ছে..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"আপনার আইটি প্রশাসক এই ডিভাইসটির সমস্যা নিবারণে সহায়তা করতে একটি ত্রুটির প্রতিবেদন চেয়েছেন৷ অ্যাপ্লিকেশানগুলি এবং ডেটা শেয়ার করা হতে পারে এবং আপনার ডিভাইসটিকে অস্থায়ীভাবে ধীর করে দিতে পারে৷"</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"আপনার আইটি প্রশাসক এই ডিভাইসটির সমস্যা নিবারণে সহায়তা করতে একটি ত্রুটির প্রতিবেদন চেয়েছেন৷ অ্যাপ্লিকেশান এবং ডেটা শেয়ার করা হতে পারে৷"</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"এটি অস্থায়ীভাবে আপনার ডিভাইসটিকে ধীর করে দিতে পারে"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"স্বীকার করুন"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"অস্বীকার করুন"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"কীবোর্ড পরিবর্তন করুন"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"কীবোর্ড চয়ন করুন"</string>
<string name="show_ime" msgid="2506087537466597099">"ফিজিক্যাল কীবোর্ড সক্রিয় থাকার সময় এটিকে স্ক্রীনে রাখুন"</string>
diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
index 798f6f5..61ea35c 100644
--- a/core/res/res/values-bs-rBA/strings.xml
+++ b/core/res/res/values-bs-rBA/strings.xml
@@ -1060,13 +1060,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Dodirnite za više opcija."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Uređaj za USB otklanjanje grešaka povezan"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dodirnite da biste onemogućili USB otklanjanje grešaka."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Podijeliti izvještaj o grešci?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Dijeljenje izvještaja o grešci..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Vaš IT administrator je zatražio izvještaj o grešci kako bi pomogao riješiti problem na ovom uređaju. To može uzrokovati dijeljenje aplikacija i podataka te privremeno usporiti vaš uređaj."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Vaš IT administrator je zatražio izvještaj o grešci kako bi pomogao u rješavanju problema ovog uređaja. Aplikacije i podaci se mogu dijeliti."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"To može privremeno usporiti vaš uređaj"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRIHVATI"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODBACI"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Promijeni tastaturu"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Odaberite tastature"</string>
<string name="show_ime" msgid="2506087537466597099">"Prikaži na ekranu dok je fizička tastatura aktivna"</string>
@@ -1558,7 +1561,7 @@
</plurals>
<string name="importance_from_user" msgid="7318955817386549931">"Vi određujete značaj ovih obavještenja."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Ovo je značajno zbog osoba koje su uključene."</string>
- <string name="user_creation_account_exists" msgid="1942606193570143289">"Da li dozvoljate da <xliff:g id="APP">%1$s</xliff:g> kreira novog korisnika za nalog <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="user_creation_account_exists" msgid="1942606193570143289">"Da li dozvoljavate aplikaciji <xliff:g id="APP">%1$s</xliff:g> da kreira novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Da li dozvoljavate da <xliff:g id="APP">%1$s</xliff:g> kreira novog korisnika za <xliff:g id="ACCOUNT">%2$s</xliff:g> (Korisnik sa ovim nalogom već postoji)?"</string>
<string name="language_selection_title" msgid="2680677278159281088">"Dodaj jezik"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Izbor regije"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 9bd8014..3c32e9a 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toca per veure més opcions."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuració USB activada"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toca per desactivar la depuració USB"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vols compartir l\'informe d\'errors?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"S\'està compartint l\'informe d\'errors…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"L\'administrador de TI ha sol·licitat un informe d\'errors per resoldre els problemes d\'aquest dispositiu. És possible que es comparteixin aplicacions i dades, i que el dispositiu funcioni més a poc a poc durant una estona."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"El teu administrador de TI ha sol·licitat un informe d\'errors per resoldre els problemes d\'aquest dispositiu. És possible que es comparteixin aplicacions i dades."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"És possible que el dispositiu funcioni més a poc a poc durant una estona"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTA"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REBUTJA"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Canvia el teclat"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Tria els teclats"</string>
<string name="show_ime" msgid="2506087537466597099">"El deixa a la pantalla mentre el teclat físic està actiu"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index facf368..9d3ecff 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1068,13 +1068,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Klepnutím zobrazíte další možnosti."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Ladění přes USB připojeno"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dotykem zakážete ladění USB."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Sdílet zprávu o chybě?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sdílení zprávy o chybě…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Administrátor IT si vyžádal zprávu o chybě, aby mohl problém odstranit. Mohou být sdíleny aplikace a data a zařízení se může dočasně zpomalit."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Administrátor IT si vyžádal zprávu o chybě, aby mohl problém odstranit. Aplikace a data mohou být sdílena."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Zařízení se může dočasně zpomalit"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PŘIJMOUT"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODMÍTNOUT"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Změna klávesnice"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Vybrat klávesnici"</string>
<string name="show_ime" msgid="2506087537466597099">"Ponechat na obrazovce, když je aktivní fyzická klávesnice"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index a0a3f8f..2ee9afd 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Tryk for at se flere muligheder."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-fejlretning er tilsluttet"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Tryk for at deaktivere USB-fejlretning."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vil du dele fejlrapporten?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deler fejlrapport…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Din it-administrator har anmodet om en fejlrapport for bedre at kunne finde og rette fejlen på enheden. Apps og data deles muligvis, og din enhed kan midlertidigt blive langsommere."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Din it-administrator har anmodet om en fejlrapport for bedre at kunne finde og rette fejlen på enheden. Apps og data deles muligvis."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Dette kan midlertidigt gøre enheden langsommere"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTÉR"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"AFVIS"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Skift tastatur"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Vælg tastaturer"</string>
<string name="show_ime" msgid="2506087537466597099">"Behold den på skærmen, mens det fysiske tastatur er aktivt"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 8406a70..c9874b8 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Für weitere Optionen tippen"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-Debugging"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Zum Deaktivieren berühren"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Fehlerbericht teilen?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Fehlerbericht wird geteilt…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Dein IT-Administrator hat einen Fehlerbericht zur Fehlerbehebung dieses Geräts angefordert. Apps und Daten werden unter Umständen geteilt und dein Gerät wird möglicherweise vorübergehend langsamer."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Dein IT-Administrator hat einen Fehlerbericht zur Fehlerbehebung dieses Geräts angefordert. Apps und Daten werden unter Umständen geteilt."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Dadurch wird dein Gerät möglicherweise vorübergehend langsamer"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"AKZEPTIEREN"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ABLEHNEN"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Tastatur ändern"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Tastatur auswählen"</string>
<string name="show_ime" msgid="2506087537466597099">"Auf dem Display einblenden, wenn die physische Tastatur aktiv ist"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index f5192b7..1cac5e5 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Αγγίξτε για περισσότερες επιλογές."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Συνδέθηκε ο εντοπισμός σφαλμάτων USB"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Απεν. του εντοπ. σφαλμάτων USB."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Κοινή χρήση αναφοράς σφάλματος;"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Κοινή χρήση αναφοράς σφάλματος…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Ο διαχειριστής σας IT ζήτησε μια αναφορά σφάλματος για να συμβάλει στην αντιμετώπιση του προβλήματος αυτής της συσκευής. Ενδέχεται να γίνει κοινή χρήση των εφαρμογών και να επιβραδυνθεί προσωρινά τη λειτουργία της συσκευής σας."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Ο διαχειριστής σας IT ζήτησε μια αναφορά σφάλματος για να συμβάλει στην αντιμετώπιση του προβλήματος αυτής της συσκευής. Ενδέχεται να γίνει κοινή χρήση των εφαρμογών και των δεδομένων."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Αυτή η διαδικασία ενδέχεται να επιβραδύνει προσωρινά τη λειτουργία της συσκευής σας"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ΑΠΟΔΟΧΗ"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ΑΠΟΡΡΙΨΗ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Αλλαγή πληκτρολογίου"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Επιλογή πληκτρολογίων"</string>
<string name="show_ime" msgid="2506087537466597099">"Να παραμένει στην οθόνη όταν είναι ενεργό το φυσικό πληκτρολόγιο"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 7fdf1c1..a6c0e65 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1052,13 +1052,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Touch for more options."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Touch to disable USB debugging."</string>
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Taking bug report…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Share bug report?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sharing bug report…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"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>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"This may temporarily slow down your device"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPT"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"DECLINE"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHARE"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"DECLINE"</string>
<string name="select_input_method" msgid="8547250819326693584">"Change keyboard"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Choose keyboards"</string>
<string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 7fdf1c1..a6c0e65 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1052,13 +1052,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Touch for more options."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Touch to disable USB debugging."</string>
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Taking bug report…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Share bug report?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sharing bug report…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"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>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"This may temporarily slow down your device"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPT"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"DECLINE"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHARE"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"DECLINE"</string>
<string name="select_input_method" msgid="8547250819326693584">"Change keyboard"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Choose keyboards"</string>
<string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 7fdf1c1..a6c0e65 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1052,13 +1052,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Touch for more options."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Touch to disable USB debugging."</string>
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Taking bug report…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Share bug report?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sharing bug report…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"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>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"This may temporarily slow down your device"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPT"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"DECLINE"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHARE"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"DECLINE"</string>
<string name="select_input_method" msgid="8547250819326693584">"Change keyboard"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Choose keyboards"</string>
<string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index b101ded..e389a22 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -239,7 +239,7 @@
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceder a los contactos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Ubicación"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"acceso a la ubicación de este dispositivo"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"acceder a la ubicación de este dispositivo"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendario"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"acceder al calendario"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toca para ver más opciones."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración por USB conectada"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toca para desactivar la depuración por USB."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"¿Compartir informe de errores?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartiendo informe de errores…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"El administrador de TI solicitó un informe de errores para ayudar a solucionar los problemas de este dispositivo. Es posible que se compartan apps y datos, y que el dispositivo se ralentice temporalmente."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"El administrador de TI solicitó un informe de errores para ayudar a solucionar los problemas de este dispositivo. Es posible que se compartan apps y datos."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Es posible que tu dispositivo se ralentice temporalmente"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEPTAR"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECHAZAR"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Cambiar el teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Seleccionar teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Mantener en la pantalla cuando el teclado físico está activo"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 6b2c0f8..c4d1ffd 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toca para obtener más opciones"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración USB habilitada"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toca aquí para inhabilitarla"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"¿Compartir informe de errores?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartiendo informe de errores…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Tu administrador de TI ha solicitado un informe de errores para solucionar problemas de este dispositivo. Es posible que se compartan las aplicaciones y los datos. Puede que el dispositivo funcione más lento de forma temporal."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Tu administrador de TI ha solicitado un informe de errores para solucionar problemas de este dispositivo. Es posible que se compartan las aplicaciones y los datos."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Puede que el dispositivo funcione más lento de forma temporal"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEPTAR"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECHAZAR"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Cambiar teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Elegir teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Debe seguir en pantalla mientras el teclado físico esté activo"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 0236d2c..f2faf00 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Puudutage rohkemate valikute kuvamiseks."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-silumine ühendatud"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Puudutage USB-silumise keelamiseks."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Kas jagada veaaruannet?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Veaaruande jagamine …"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IT-administraator taotles veaaruannet, mis aitaks seadmes vigu otsida. Rakendusi ja andmeid võidakse jagada ja see võib ajutiselt teie seadet aeglustada."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IT-administraator taotles veaaruannet, mis aitaks seadmes vigu otsida. Rakendusi ja andmeid võidakse jagada."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"See võib ajutiselt teie seadet aeglustada"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"NÕUSTU"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"KEELDU"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Klaviatuuri muutmine"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Vali klaviatuurid"</string>
<string name="show_ime" msgid="2506087537466597099">"Hoia seda ekraanil, kui füüsiline klaviatuur on aktiivne"</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 67776e7..a24831a 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Ukitu aukera gehiago ikusteko."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB arazketa konektatuta"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB arazketa desgaitzeko, ukitu hau."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Akatsen txostena partekatu nahi duzu?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Akatsen txostena partekatzen…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IKT administratzaileak akatsen txostena eskatu du gailuko arazoa konpontzeko. Baliteke aplikazioak eta datuak partekatzea, eta agian motelago ibiliko da gailua aldi batez."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IKT administratzaileak akatsen txostena eskatu du gailuko arazoa konpontzeko. Baliteke aplikazioak eta datuak partekatzea."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Agian motelago ibiliko da gailua aldi batez"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ONARTU"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"BAZTERTU"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Aldatu teklatua"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Aukeratu teklatuak"</string>
<string name="show_ime" msgid="2506087537466597099">"Erakutsi pantailan teklatu fisikoa aktibo dagoen bitartean"</string>
@@ -1468,7 +1471,7 @@
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Eskatu desblokeatzeko eredua aingura kendu aurretik"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Eskatu pasahitza aingura kendu aurretik"</string>
<string name="dock_forced_resizable" msgid="5914261505436217520">"Baliteke aplikazioak ez funtzionatzea pantaila zatituan."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikazioak ez du onartzen pantaila banatua"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikazioak ez du onartzen pantaila zatitua"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Administratzaileak instalatu du"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Administratzaileak eguneratu du"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Administratzaileak ezabatu du"</string>
@@ -1541,7 +1544,7 @@
<string name="importance_from_person" msgid="9160133597262938296">"Garrantzitsua da eragiten dien pertsonengatik."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> aplikazioari <xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzea baimendu nahi diozu?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> aplikazioari <xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzea baimendu nahi diozu? (Badago kontu hori duen erabiltzaile bat)"</string>
- <string name="language_selection_title" msgid="2680677278159281088">"Gehitu hizkuntza bat"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Gehitu hizkuntza"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Lurralde-hobespena"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Adierazi hizkuntza"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Iradokitakoak"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index feae1ca..17a5f5b 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"برای گزینههای بیشتر لمس کنید."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"اشکالزدایی USB متصل شد"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"غیرفعالکردن اشکالزداییUSB: با لمس آن."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"گزارش اشکال به اشتراک گذاشته شود؟"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"درحال اشتراکگذاری گزارش اشکال…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"سرپرست فناوری اطلاعات شما برای کمک به عیبیابی این دستگاه، درخواست گزارش اشکال کرده است. ممکن است برنامهها و دادهها به اشتراک گذاشته شوند و سرعت دستگاهتان بهطور موقت کاهش یابد."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"سرپرست فناوری اطلاعات شما برای کمک به عیبیابی این دستگاه، گزارش اشکال درخواست کرده است. ممکن است برنامهها و دادهها به اشتراک گذاشته شوند."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"ممکن است سرعت دستگاهتان بهطور موقت کاهش یابد"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"پذیرفتن"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"نپذیرفتن"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"تغییر صفحهکلید"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"انتخاب صفحهکلیدها"</string>
<string name="show_ime" msgid="2506087537466597099">"وقتی صفحهکلید فیزیکی فعال است این ویرایشگر را روی صفحه نگهمیدارد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 2f0a361..15cba76b 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Lisää vaihtoehtoja koskettamalla"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-vianetsintä yhdistetty"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Sulje USB-vianetsintä koskettamalla."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Jaetaanko virheraportti?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Jaetaan virheraporttia…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Järjestelmänvalvoja pyysi virheraporttia voidakseen auttaa laitteen vianetsinnässä. Sovelluksia ja tietoja voidaan jakaa, ja laitteen toiminta voi hidastua väliaikaisesti."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Järjestelmänvalvoja pyysi virheraporttia voidakseen auttaa laitteen vianetsinnässä. Sovelluksia ja tietoja voidaan jakaa."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Tämä voi hidastaa laitteen toimintaa väliaikaisesti."</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"HYVÄKSY"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"HYLKÄÄ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Vaihda näppäimistö"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Valitse näppäimistöt"</string>
<string name="show_ime" msgid="2506087537466597099">"Pidä näytöllä, kun fyysinen näppäimistö on aktiivinen."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 4dce7e6..83e7936 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Touchez pour afficher plus d\'options."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB connecté"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Appuyez pour désactiver le débogage USB."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Partager le rapport de bogue?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Partage du rapport de bogue en cours..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Votre administrateur informatique a demandé un rapport de bogue pour l\'aider à dépanner cet appareil. Les applications et les données peuvent être partagées. Cela pourrait temporairement ralentir votre appareil."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Votre administrateur informatique a demandé un rapport de bogue pour l\'aider à dépanner cet appareil. Les applications et les données peuvent être partagées."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Cela pourrait temporairement ralentir votre appareil."</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTER"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REFUSER"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Changer de clavier"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Choisir les claviers"</string>
<string name="show_ime" msgid="2506087537466597099">"Afficher lorsque le clavier physique est activé"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index c8ef7d0..2e047ad 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Appuyez pour afficher plus d\'options"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB activé"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Appuyez pour désact. débogage USB"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Partager le rapport de bug ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Partage du rapport de bug…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Votre administrateur informatique a demandé un rapport de bug pour l\'aider à résoudre le problème lié à cet appareil. Il est possible que des applications et des données soient partagées et que votre appareil ralentisse temporairement."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Votre administrateur informatique a demandé un rapport de bug pour l\'aider à résoudre le problème lié à cet appareil. Il est possible que des applications et des données soient partagées."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Ceci risque de ralentir temporairement votre appareil."</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTER"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REFUSER"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Changer de clavier"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Sélectionner des claviers"</string>
<string name="show_ime" msgid="2506087537466597099">"Afficher lorsque le clavier physique est activé"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 41c600d..e721037 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toca para ver máis opcións."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración USB conectada"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toca aquí para desactivala"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Queres compartir o informe de erros?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartindo informe de erros..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"O teu administrador de TI solicitou un informe de erros para axudar a solucionar os problemas deste dispositivo. É posible que se compartan aplicacións e datos e que se reduza a velocidade do teu dispositivo temporalmente."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"O teu administrador de TI solicitou un informe de erros para axudar a solucionar os problemas deste dispositivo. É posible que se compartan aplicacións e datos."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Esta acción pode reducir a velocidade do teu dispositivo temporalmente"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEPTAR"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ANULAR"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Cambiar teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Seleccionar teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manteno na pantalla mentres o teclado físico estea activo"</string>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index 0bda139..6b05537 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"વધુ વિકલ્પો માટે ટચ કરો."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ડીબગિંગ કનેક્ટ થયું."</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ડીબગિંગ અક્ષમ કરવા માટે ટચ કરો."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"બગ રિપોર્ટ શેર કરીએ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"બગ રિપોર્ટ શેર કરી રહ્યાં છે…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"તમારા IT વ્યવસ્થાપક એ આ ઉપકરણની સમસ્યા નિવારણમાં સહાય માટે બગ રિપોર્ટની વિનંતી કરી છે. ઍપ્લિકેશનો અને ડેટા શેર કરવામાં આવી શકે છે અને તમારા ઉપકરણને અસ્થાયી રૂપે ધીમું કરી શકે છે."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"તમારા IT વ્યવસ્થાપક એ આ ઉપકરણની સમસ્યા નિવારણમાં સહાય માટે બગ રિપોર્ટની વિનંતી કરી છે. ઍપ્લિકેશનો અને ડેટા શેર કરવામાં આવી શકે છે."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"આ અસ્થાયી રૂપે તમારા ઉપકરણને ધીમું કરી શકે છે"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"સ્વીકારો"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"નકારો"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"કીબોર્ડ બદલો"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"કીબોર્ડ્સ પસંદ કરો"</string>
<string name="show_ime" msgid="2506087537466597099">"જ્યારે ભૌતિક કીબોર્ડ સક્રિય હોય ત્યારે તેને સ્ક્રીન પર રાખો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 995c9c7..6c55445 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"और विकल्पों के लिए स्पर्श करें."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB डीबग कनेक्ट किया गया"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB डीबग करना अक्षम करने के लिए स्पर्श करें."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग रिपोर्ट साझा करें?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"बग रिपोर्ट साझा की जा रही है…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"इस डिवाइस के समस्या निवारण में सहायता हेतु आपके आईटी व्यवस्थापक ने बग रिपोर्ट के लिए अनुरोध किया है. ऐप्स और डेटा को साझा किया जा सकता है और आपके डिवाइस की गति अस्थायी रूप से धीमी हो सकती है."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"आपके आईटी व्यवस्थापक ने इस डिवाइस के समस्या निवारण में सहायता के लिए एक बग रिपोर्ट का अनुरोध किया है. ऐप्स और डेटा साझा किए जा सकते हैं."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"इससे आपका डिवाइस अस्थायी रूप से धीमा हो सकता है"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"स्वीकार करें"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"अस्वीकार करें"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"कीबोर्ड बदलें"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"कीबोर्ड चुनें"</string>
<string name="show_ime" msgid="2506087537466597099">"भौतिक कीबोर्ड के सक्रिय होने के दौरान इसे स्क्रीन पर बनाए रखें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 823181d..c32c5ee 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1060,13 +1060,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Dodirnite za više opcija."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Priključen je alat za uklanjanje pogrešaka USB-om"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dodirnite da se onemogući otklanjanje pogrešaka USB-om."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Želite li podijeliti izvješće o programskoj pogrešci?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Dijeljenje izvješća o programskoj pogrešci…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IT administrator zatražio je izvješće o programskoj pogrešci radi lakšeg rješavanja problema na uređaju. Moguće je da će se aplikacije i podaci dijeliti, što bi moglo privremeno usporiti uređaj."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IT administrator zatražio je izvješće o programskoj pogrešci radi lakšeg rješavanja problema na uređaju. Moguće je da će se aplikacije i podaci dijeliti."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"To bi moglo privremeno usporiti uređaj"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRIHVATI"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODBIJ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Promjena tipkovnice"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Odaberi tipkovnice"</string>
<string name="show_ime" msgid="2506087537466597099">"Zadržava se na zaslonu dok je fizička tipkovnica aktivna"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 015e13d..91f5280 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Érintse meg a további lehetőségekhez."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB hibakereső csatlakoztatva"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Érintse meg az USB hibakeresés kikapcsolásához."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Megosztja a hibajelentést?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Hibajelentés megosztása…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"A rendszergazda hibajelentést kért, hogy segíthessen az eszközzel kapcsolatos probléma megoldásában. Előfordulhat, hogy a rendszer megosztja az alkalmazásokat és adatokat, továbbá eszköze átmenetileg lelassulhat."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"A rendszergazda hibajelentést kért, hogy segíthessen az eszközzel kapcsolatos probléma megoldásában. Előfordulhat, hogy a rendszer megosztja az alkalmazásokat és adatokat."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Előfordulhat, hogy eszköze emiatt átmenetileg lelassul"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ELFOGADOM"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ELUTASÍTOM"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Billentyűzet megváltoztatása"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Billentyűzetek kiválasztása"</string>
<string name="show_ime" msgid="2506087537466597099">"Maradjon a képernyőn, amíg a billentyűzet aktív"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 3a56491..f009c7b 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Հպեք՝ լրացուցիչ ընտրանքների համար:"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB վրիպազերծումը միացված է"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Հպեք` USB կարգաբերումը կասեցնելու համար:"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Տրամադրե՞լ վրիպակի զեկույցը:"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Վրիպակի զեկույցի տրամադրում…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Այս սարքի անսարքությունների վերացման նպատակով ձեր ՏՏ ադմինիստրատորին անհրաժեշտ է վրիպակի զեկույց: Կարող են տրամադրվել տեղեկություններ ձեր հավելվածների մասին և այլ տվյալներ, իսկ սարքի աշխատանքը կարող է ժամանակավորապես դանդաղել:"</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Այս սարքի անսարքությունների վերացման նպատակով ձեր ՏՏ ադմինիստրատորին անհրաժեշտ է վրիպակի զեկույց: Կարող են տրամադրվել տեղեկություններ ձեր հավելվածներնի մասին և այլ տվյալներ:"</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Այդ ընթացքում ձեր սարքի աշխատանքը կարող է դանդաղել"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ԸՆԴՈՒՆԵԼ"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ՄԵՐԺԵԼ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Փոխել ստեղնաշարը"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Ընտրել ստեղնաշար"</string>
<string name="show_ime" msgid="2506087537466597099">"Պահել էկրանին մինչդեռ ֆիզիկական ստեղնաշարն ակտիվ է"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 2391ef7..8351f343 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1052,13 +1052,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Sentuh untuk opsi lainnya."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Debugging USB terhubung"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Sentuh untuk menonaktifkan debugging USB."</string>
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Mengambil laporan bug…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Bagikan laporan bug?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Membagikan laporan bug..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Admin IT meminta laporan bug untuk membantu memecahkan masalah perangkat ini. Aplikasi dan data mungkin dibagikan dan untuk sementara perangkat mungkin menjadi lambat."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Admin IT meminta laporan bug untuk membantu memecahkan masalah perangkat ini. Aplikasi dan data mungkin dibagikan."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Tindakan ini mungkin memperlambat perangkat untuk sementara"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"SETUJU"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"TOLAK"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Admin IT meminta laporan bug untuk membantu memecahkan masalah perangkat ini. Aplikasi dan data mungkin dibagikan."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"BAGIKAN"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"TOLAK"</string>
<string name="select_input_method" msgid="8547250819326693584">"Ubah keyboard"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Pilih keyboard"</string>
<string name="show_ime" msgid="2506087537466597099">"Pertahankan di layar jika keyboard fisik masih aktif"</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 8246584..f43adcf 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Snertu til að fá fleiri valkosti."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-villuleit tengd"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Snertu til að slökkva á USB-villuleit."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Deila villutilkynningu?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deilir villutilkynningu..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Kerfisstjórinn þinn óskaði eftir villutilkynningu til að auðvelda úrræðaleit á þessu tæki. Forritum og gögnum verður hugsanlega deilt og mögulegt er að þetta hægi tímabundið á tækinu."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Kerfisstjórinn þinn óskaði eftir villutilkynningu til að auðvelda úrræðaleit á þessu tæki. Forritum og gögnum verður hugsanlega deilt."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Hugsanlega hægir þetta tímabundið á tækinu þínu"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"SAMÞYKKJA"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"HAFNA"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Skipta um lyklaborð"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Velja lyklaborð"</string>
<string name="show_ime" msgid="2506087537466597099">"Haltu því á skjánum meðan vélbúnaðarlyklaborðið er virkt"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 912f154..9e02d34 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Tocca per visualizzare più opzioni."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Debug USB collegato"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Tocca per disattivare il debug USB."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Condividere la segnalazione di bug?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Condivisione della segnalazione di bug…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"L\'amministratore IT ha richiesto una segnalazione di bug per poter risolvere più facilmente i problemi di questo dispositivo. Potrebbero essere condivisi dati e app e il dispositivo potrebbe rallentare temporaneamente."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"L\'amministratore IT ha richiesto una segnalazione di bug per poter risolvere più facilmente i problemi di questo dispositivo. Potrebbero essere condivisi dati e app."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Il dispositivo potrebbe rallentare temporaneamente"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCETTO"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RIFIUTO"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Cambia tastiera"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Scegli tastiera"</string>
<string name="show_ime" msgid="2506087537466597099">"Tieni sullo schermo quando è attiva la tastiera fisica"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index c334a3c..48c4c29 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1068,13 +1068,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"גע להצגת עוד אפשרויות."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"ניפוי באגים של USB מחובר"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"גע כדי להשבית ניפוי באגים בהתקן ה-USB."</string>
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"עיבוד דוח על באג..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"האם לשתף דוח על באג?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"שיתוף דוח על באג…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"מנהל ה-IT ביקש דוח על באג כדי לסייע בפתרון בעיות במכשיר זה. ייתכן שאפליקציות ונתונים ישותפו. פעילות המכשיר עשויה להאט באופן זמני."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"מנהל ה-IT שלך ביקש דוח על באג כדי לסייע בפתרון בעיות במכשיר זה. ייתכן שאפליקציות ונתונים ישותפו."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"קצב הפעולה של המכשיר עשוי להיות איטי יותר באופן זמני כתוצאה מכך"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"אישור"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"דחייה"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"מנהל ה-IT שלך ביקש דוח על באג כדי לסייע בפתרון בעיות במכשיר זה. ייתכן שאפליקציות ונתונים ישותפו."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"שתף"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"דחה"</string>
<string name="select_input_method" msgid="8547250819326693584">"שינוי מקלדת"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"בחר מקלדות"</string>
<string name="show_ime" msgid="2506087537466597099">"השאר אותו במסך בזמן שהמקלדת הפיזית פעילה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 9ee8e0e..810d70d 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1053,13 +1053,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"タップしてその他のオプションを表示"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USBデバッグが接続されました"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"タップしてUSBデバッグを無効化"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"バグレポートを共有しますか?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"バグレポートの共有中…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IT 管理者からこの端末のトラブルシューティングに役立てるためバグレポートを共有するようリクエストがありました。アプリやデータが共有され、端末の動作が一時的に遅くなる場合があります。"</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IT 管理者からこの端末のトラブルシューティングに役立てるためバグレポートを共有するようリクエストがありました。アプリやデータが共有されることがあります。"</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"共有によって端末の動作が一時的に遅くなる場合があります"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"同意する"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"同意しない"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"キーボードの変更"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"キーボードの選択"</string>
<string name="show_ime" msgid="2506087537466597099">"物理キーボードが有効になっている間は、画面に表示されます"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 8e4e378..0b164eb 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"შეეხეთ დამატებითი პარამეტრებისთვის."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB გამართვა შეერთებულია"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"შეეხეთ, რათა შეწყვიტოთ USB-ის გამართვა."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"გსურთ ხარვეზის შესახებ ანგარიშის გაზიარება?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"მიმდინარეობს ხარვეზის შესახებ ანგარიშის გაზიარება…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"ამ მოწყობილობის პრობლემების აღმოფხვრაში დასახმარებლად, თქვენი IT ადმინისტრატორი ხარვეზის შესახებ ანგარიშს ითხოვს, რა დროსაც შეიძლება გაზიარდეს აპები და მონაცემები, ხოლო თქვენი მოწყობილობა დროებით შენელდეს."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"ამ მოწყობილობის პრობლემების აღმოფხვრაში დასახმარებლად, თქვენი IT ადმინისტრატორი ხარვეზის შესახებ ანგარიშს ითხოვს, რა დროსაც შეიძლება გაზიარდეს აპები და მონაცემები."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"ამან შეიძლება დროებით შეანელოს თქვენი მოწყობილობა"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"მიღება"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"უარყოფა"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"კლავიატურის შეცვლა"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"კლავიატურების არჩევა"</string>
<string name="show_ime" msgid="2506087537466597099">"აქტიური ფიზიკური კლავიატურისას ეკრანზე შენარჩუნება"</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index c14bc68..d803c50 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -1052,13 +1052,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Қосымша параметрлер үшін түртіңіз."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB жөндеу қосылған"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB жөндеуді өшіру үшін түртіңіз."</string>
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Қате туралы есеп құрылуда…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Қате туралы есепті бөлісу керек пе?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Қате туралы есеп бөлісілуде…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"АТ әкімшісі осы құрылғы ақауларын жоюға көмектесу үшін қате туралы есепті сұрады. Қолданбалар және деректер бөлісілуі әрі құрылғының жұмысы уақытша баяулауы мүмкін."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"АТ әкімшісі осы құрылғы ақауларын жоюға көмектесу үшін қате туралы есепті сұрады. Қолданбалар және деректер бөлісілуі мүмкін."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Бұл құрылғы жұмысын уақытша баяулатуы мүмкін"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ҚАБЫЛДАУ"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ҚАБЫЛДАМАУ"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"АТ әкімшісі осы құрылғы ақауларын жоюға көмектесу үшін қате туралы есепті сұрады. Қолданбалар және деректер бөлісілуі мүмкін."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"БӨЛІСУ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ҚАБЫЛДАМАУ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Пернетақтаны өзгерту"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Пернетақталарды таңдау"</string>
<string name="show_ime" msgid="2506087537466597099">"Физикалық пернетақта белсенді кезде оны экранда ұстау"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 0becd32..9f9e961 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -1054,13 +1054,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ប៉ះដើម្បីបានជម្រើសថែមទៀត។"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"បានភ្ជាប់ការកែកំហុសយូអេសប៊ី"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"ប៉ះ ដើម្បីបិទការកែកំហុសយូអេសប៊ី។"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ចែករំលែករបាយការណ៍កំហុសឬ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"កំពុងចែករំលែករបាយកំហុស…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"អ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកបានស្នើរបាយការណ៍កំហុសដើម្បីដោះស្រាយកំហុសឧបករណ៍នេះ។ កម្មវិធី និងទិន្នន័យអាចនឹងត្រូវបានចែករំលែក ហើយឧបករណ៍របស់អ្នកអាចនឹងយឺតជាបណ្តោះអាសន្ន។"</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"អ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកបានស្នើរបាយការណ៍កំហុសដើម្បីដោះស្រាយកំហុសឧបករណ៍នេះ។ កម្មវិធី និងទិន្នន័យអាចនឹងត្រូវបានចែករំលែក។"</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"វាអាចនឹងធ្វើឲ្យឧបករណ៍របស់អ្នកយឺតជាបណ្តោះអាសន្ន។"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ព្រមទទួល"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"បដិសេធ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"ប្ដូរក្ដារចុច"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"ជ្រើសក្ដារចុច"</string>
<string name="show_ime" msgid="2506087537466597099">"ទុកវានៅលើអេក្រង់ខណៈពេលក្តារចុចពិតប្រាកដកំពុងសកម្ម"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index eeb156c..46ef931 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗೆ ಸ್ಪರ್ಶಿಸಿ."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ಡೀಬಗಿಂಗ್ ಸಂಪರ್ಕ"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ಡೀಬಗಿಂಗ್ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಸ್ಪರ್ಶಿಸಿ."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ಬಗ್ ವರದಿಯನ್ನು ಹಂಚುವುದೇ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ಬಗ್ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"ಈ ಸಾಧನದ ಸಮಸ್ಯೆ ನಿವಾರಿಸುವುದಕ್ಕೆ ಸಹಾಯ ಮಾಡಲು ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರು ಬಗ್ ವರದಿಯನ್ನು ವಿನಂತಿಸಿದ್ದಾರೆ. ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಹಂಚಿಕೊಳ್ಳಬಹುದು ಹಾಗು ನಿಮ್ಮ ಸಾಧನವು ತಾತ್ಕಾಲಿಕವಾಗಿ ನಿಧಾನಗೊಳ್ಳಬಹುದು."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"ಈ ಸಾಧನದ ಸಮಸ್ಯೆ ನಿವಾರಿಸಲು ಸಹಾಯ ಮಾಡಲು ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರು ಬಗ್ ವರದಿಯನ್ನು ವಿನಂತಿಸಿದ್ದಾರೆ. ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಹಂಚಿಕೊಳ್ಳಬಹುದು."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"ಇದು ನಿಮ್ಮ ಸಾಧನವನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ನಿಧಾನಗೊಳಿಸಬಹುದು"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ಸಮ್ಮತಿಸು"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ತಿರಸ್ಕರಿಸು"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"ಕೀಬೋರ್ಡ್ ಬದಲಿಸಿ"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"ಕೀಬೋರ್ಡ್ಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="show_ime" msgid="2506087537466597099">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್ ಸಕ್ರಿಯವಾಗಿರುವಾಗ ಅದನ್ನು ಪರದೆಯ ಮೇಲೆ ಇರಿಸಿಕೊಳ್ಳಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 3496962..f8d0598 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"더 많은 옵션을 확인하려면 터치하세요."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB 디버깅 연결됨"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB 디버깅을 사용하지 않으려면 터치하세요."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"버그 보고서를 공유하시겠습니까?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"버그 신고서 공유 중..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IT 관리자가 이 기기의 문제해결을 위해 버그 신고서를 요청했습니다. 앱과 데이터가 공유될 수 있으며 기기 속도가 일시적으로 느려질 수 있습니다."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IT 관리자가 이 기기의 문제해결을 위해 버그 보고서를 요청했습니다. 앱과 데이터가 공유될 수 있습니다."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"이로 인해 일시적으로 기기 속도가 느려질 수 있습니다."</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"수락"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"거절"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"키보드 변경"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"키보드 선택"</string>
<string name="show_ime" msgid="2506087537466597099">"물리적 키보드가 활성 상태인 경우 화면에 켜 둠"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 018e054..8670af0 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -1053,13 +1053,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Көбүрөөк параметр үчүн тийип коюңуз."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB мүчүлүштүктөрдү оңдоо туташтырылган"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB мүчүлүштүктөрдү жоюу мүмкүнчүлүгүн өчүрүү үчүн тийип коюңуз."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Мүчүлүштүк тууралуу баяндама бөлүшүлсүнбү?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Мүчүлүштүк тууралуу баяндама бөлүшүлүүдө…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Бул түзмөктүн бузулууларын аныктап оңдоо үчүн IT администраторуңуз мүчүлүштүктөр тууралуу маалыматты сурап жатат. Колдонмолор менен дайындар бөлүшүлүп, түзмөгүңүз жайыраак иштеп калышы мүмкүн."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Бул түзмөктүн бузулууларын аныктап оңдоо үчүн IT администраторуңуз мүчүлүштүктөр тууралуу маалыматты сурап жатат. Колдонмолор менен дайындар бөлүшүлүшү мүмкүн."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Ушуну менен түзмөгүңүздүн ылдамдыгы убактылуу төмөндөйт"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"КАБЫЛ АЛУУ"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ЧЕТКЕ КАГУУ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Баскычтопту өзгөртүү"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Баскычтопторду тандаңыз"</string>
<string name="show_ime" msgid="2506087537466597099">"Баскычтоп иштетилгенде экранда көрүнүп турсун"</string>
@@ -1468,7 +1471,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Бошотуудан мурун PIN суралсын"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Бошотуудан мурун кулпуну ачкан үлгү суралсын"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Бошотуудан мурун сырсөз суралсын"</string>
- <string name="dock_forced_resizable" msgid="5914261505436217520">"Колдонмо бөлүнгөн экранда иштебей калышы мүмкүн."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Колдонмодо экран бөлүнбөшү мүмкүн."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Колдонмодо экран бөлүнбөйт."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Администраторуңуз тарабынан орнотулган"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Администраторуңуз жаңырткан"</string>
@@ -1542,7 +1545,7 @@
<string name="importance_from_person" msgid="9160133597262938296">"Булар сиз үчүн маанилүү адамдар."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> колдонмосу <xliff:g id="ACCOUNT">%2$s</xliff:g> каттоо эсеби менен жаңы колдонуучу түзө берсинби ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> колдонмосу <xliff:g id="ACCOUNT">%2$s</xliff:g> каттоо эсеби менен жаңы колдонуучу түзө берсинби (мындай каттоо эсеби бар колдонуучу мурунтан эле бар) ?"</string>
- <string name="language_selection_title" msgid="2680677278159281088">"Тилди кошуңуз"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Тил кошуңуз"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Чөлкөмдүк жөндөөлөр"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Тилди киргизиңиз"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Сунушталган"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index abe9b3f..8f9d820 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -1052,13 +1052,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ສຳພັດສຳລັບທາງເລືອກເພີ່ມເຕີມ."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"ເຊື່ອມຕໍ່ການດີບັ໊ກຜ່ານ USB ແລ້ວ"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"ແຕະເພື່ອປິດການດີບັ໊ກຜ່ານ USB."</string>
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ກຳລັງຂໍລາຍງານຂໍ້ຜິດພາດ…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ແບ່ງປັນລາຍງານບັນຫາບໍ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ກຳລັງແບ່ງປັນລາຍງານບັນຫາ…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"ຜູ້ເບິ່ງແຍງລະບົບໄອທີຂອງທ່ານໄດ້ຮ້ອງຂໍລາຍງານຂໍ້ຜິດພາດເພື່ອຊ່ວຍແກ້ໄຂບັນຫາອຸປະກອນນີ້. ແອັບ ແລະ ຂໍ້ມູນອາດຖືກແບ່ງປັນ ແລະ ອຸປະກອນຂອງທ່ານອາດເຮັດວຽກຊ້າລົງຊົ່ວຄາວ."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"ຜູ້ເບິ່ງແຍງລະບົບໄອທີຂອງທ່ານໄດ້ຮ້ອງຂໍເອົາລາຍງານບັນຫາ ເພື່ອຊ່ວຍແກ້ໄຂບັນຫາໃຫ້ອຸປະກອນນີ້. ອາດຈະມີການແບ່ງປັນແອັບ ແລະ ຂໍ້ມູນນຳ."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"ນີ້ອາດຈະເຮັດໃຫ້ອຸປະກອນຂອງທ່ານຊ້າລົງຊົ່ວຄາວ"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ຍອມຮັບ"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ປະຕິເສດ"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ຜູ້ເບິ່ງແຍງລະບົບໄອທີຂອງທ່ານໄດ້ຮ້ອງຂໍເອົາລາຍງານບັນຫາ ເພື່ອຊ່ວຍແກ້ໄຂບັນຫາໃຫ້ອຸປະກອນນີ້. ອາດຈະມີການແບ່ງປັນແອັບ ແລະ ຂໍ້ມູນນຳ."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ແບ່ງປັນ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ປະຕິເສດ"</string>
<string name="select_input_method" msgid="8547250819326693584">"ປ່ຽນແປ້ນພິມ"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"ເລືອກແປ້ນພິມ"</string>
<string name="show_ime" msgid="2506087537466597099">"ເປີດໃຊ້ໃຫ້ມັນຢູ່ໃນໜ້າຈໍໃນຂະນະທີ່ໃຊ້ແປ້ນພິມພາຍນອກຢູ່"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 8604e62..8e8f5b8 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1068,13 +1068,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Palieskite, kad būtų rodoma daugiau parinkčių."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB derinimas prijungtas"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Neleisti USB derinimo."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Bendrinti pranešimą apie riktą?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Bendrinamas pranešimas apie riktą..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Jūsų IT administratorius pateikė pranešimo apie riktą užklausą, kad galėtų padėti pašalinti triktis šiame įrenginyje. Programos bei duomenys gali būti bendrinami ir įrenginys gali laikinai lėčiau veikti."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Jūsų IT administratorius pateikė pranešimo apie riktą užklausą, kad galėtų padėti pašalinti triktis šiame įrenginyje. Programos ir duomenys gali būti bendrinami."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Dėl to įrenginys gali laikinai lėčiau veikti"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"SUTIKTI"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ATMESTI"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Klaviatūros keitimas"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Pasirinkti klaviatūras"</string>
<string name="show_ime" msgid="2506087537466597099">"Palikti ekrane, kol fizinė klaviatūra aktyvi"</string>
@@ -1579,7 +1582,7 @@
<string name="importance_from_person" msgid="9160133597262938296">"Tai svarbu dėl susijusių žmonių."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją (šią paskyrą naudojantis naudotojas jau yra)?"</string>
- <string name="language_selection_title" msgid="2680677278159281088">"Kalbos pridėjimas"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Pridėkite kalbą"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Regiono nuostata"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Įveskite kalbos pav."</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Siūloma"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index a572093..5b17105 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1060,13 +1060,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Citas opcijas"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB atkļūdošana ir pievienota."</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Iespējot USB atkļūdošanu."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vai kopīgot kļūdas pārskatu?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Notiek kļūdas pārskata kopīgošana…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Jūsu IT administrators pieprasīja kļūdas pārskatu, lai palīdzētu novērst problēmu šajā ierīcē. Var tikt kopīgotas lietotnes un dati, un jūsu ierīces darbība var īslaicīgi palēnināties."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Jūsu IT administrators pieprasīja kļūdas pārskatu, lai palīdzētu novērst problēmu šajā ierīcē. Var tikt kopīgotas lietotnes un dati."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Jūsu ierīces darbība var īslaicīgi palēnināties."</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"APSTIPRINĀT"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"NORAIDĪT"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Tastatūras maiņa"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Izvēlēties tastatūru"</string>
<string name="show_ime" msgid="2506087537466597099">"Paturēt ekrānā, kamēr ir aktīva fiziskā tastatūra"</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index a5a4ba7..d59d1f3 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Допри за повеќе опции."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Поврзано е отстранување грешки преку УСБ"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Допрете за да се оневозможи отстранувањето грешки преку USB."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Да се сподели извештајот за грешки?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Се споделува извештај за грешки…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Администраторот за информатичка технологија побара извештај за грешки за да ви помогне во отстранувањето на грешките од уредот. Апликациите и податоците можеби ќе се споделат, а уредот можеби ќе биде привремено побавен при работата."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Вашиот администратор за информатичка технологија побара извештај за грешки за да помогне со отстранување на грешките на овој уред. Апликациите и податоците може да бидат споделени."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Ова може привремено да го забави уредот"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИФАТИ"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ОДБИЈ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Измени тастатура"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Избери тастатури"</string>
<string name="show_ime" msgid="2506087537466597099">"Прикажувај го на екранот додека е активна физичката тастатура"</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 8a97930..61fadea 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് സ്പർശിക്കൂ."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ഡീബഗ്ഗിംഗ് കണക്റ്റുചെയ്തു"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ഡീബഗ്ഗിംഗ് ഓഫാക്കാൻ സ്പർശിക്കൂ."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ബഗ് റിപ്പോർട്ട് പങ്കിടണോ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ബഗ് റിപ്പോർട്ട് പങ്കിടുന്നു…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"ഈ ഉപകരണവുമായി ബന്ധപ്പെട്ട പ്രശ്നം പരിഹരിക്കുന്നതിന് നിങ്ങളുടെ ഐടി അഡ്മിൻ ഒരു ബഗ് റിപ്പോർട്ട് അഭ്യർത്ഥിച്ചു. ആപ്സും ഡാറ്റയും പങ്കിടപ്പെട്ടേക്കും, നിങ്ങളുടെ ഉപകരണത്തെ ഇത് താൽക്കാലികമായി മന്ദഗതിയിലാക്കിയേക്കാം."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"ഈ ഉപകരണത്തിലെ പ്രശ്നം പരിഹരിക്കുന്നതിന് നിങ്ങളുടെ ഐടി അഡ്മിൻ ഒരു ബഗ് റിപ്പോർട്ട് അഭ്യർത്ഥിച്ചു. ആപ്സും ഡാറ്റയും പങ്കിടപ്പെട്ടേക്കും."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"നിങ്ങളുടെ ഉപകരണത്തെ ഇത് താൽക്കാലികമായി മന്ദഗതിയിലാക്കിയേക്കാം"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"അംഗീകരിക്കുക"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"നിരസിക്കുക"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"കീബോഡ് മാറ്റുക"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"കീബോർഡുകൾ തിരഞ്ഞെടുക്കുക"</string>
<string name="show_ime" msgid="2506087537466597099">"ഫിസിക്കൽ കീബോർഡ് സജീവമായിരിക്കുമ്പോൾ സ്ക്രീനിൽ നിലനിർത്തുക"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 9950003..1f683cb 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Нэмэлт сонголтыг харахын тулд дарна."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB дебаг холбогдсон"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB дебагийг идэвхгүй болгох бол хүрнэ үү."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Алдааны тайланг хуваалцах уу?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Алдааны тайланг хуваалцаж байна..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Энэ төхөөрөмжийн асуудлыг шийдвэрлэхийнт тулд таны IT админ алдааны тайланг хүслээ. Апп болон өгөгдлийг хуваалцаж, таны төхөөрөмж бага зэрэг удаан ажиллаж болзошгүй."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Энэ төхөөрөмжийн асуудлыг шийдвэрлэхийн тулд таны IT админ алдааны тайланг хүслээ. Апп болон өгөгдлийг хуваалцсан байж болзошгүй."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Энэ нь таны төхөөрөмжийг түр хугацаанд удаашруулж болзошгүй"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ЗӨВШӨӨРӨХ"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ТАТГАЛЗАХ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Гарыг өөрчлөх"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Гар сонгох"</string>
<string name="show_ime" msgid="2506087537466597099">"Бодит гар идэвхтэй үед үүнийг дэлгэцэнд харуулна уу"</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 968331a..91b27ec 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"अधिक पर्यायांसाठी स्पर्श करा."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB डीबग करणे कनेक्ट केले"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB डीबग करणे अक्षम करण्यासाठी स्पर्श करा."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग अहवाल सामायिक करायचा?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"दोष अहवाल सामायिक करीत आहे..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"आपल्या IT प्रशासकाने या डिव्हाइसची समस्या निवारण करण्यात मदत करण्यासाठी एका दोष अहवालाची विनंती केली. अॅप्स आणि डेटा सामायिक केले जाऊ शकतात आणि आपले डिव्हाइस तात्पुरते धीमे होऊ शकते."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"आपल्या IT प्रशासकाने या डिव्हाइसच्या समस्येचे निवारण करण्यात मदत करण्यासाठी दोष अहवालाची विनंती केली. अॅप्स आणि डेटा सामायिक केला जाऊ शकतो."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"हे तात्पुरता आपले डिव्हाइस धिमे करू शकते."</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"स्वीकार करा"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"नकार द्या"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"कीबोर्ड बदला"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"कीबोर्ड निवडा"</string>
<string name="show_ime" msgid="2506087537466597099">"भौतिक कीबोर्ड सक्रिय असताना त्यास स्क्रीनवर ठेवा"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 06401bf..5555663 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Sentuh untuk mendapatkan lagi pilihan."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Penyahpepijatan USB disambungkan"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Sentuh untuk melumpuhkan penyahpepijatan USB."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Kongsi laporan pepijat?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Berkongsi laporan pepijat…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Pentadbir IT anda meminta laporan pepijat untuk membantu menyelesaikan masalah peranti ini. Apl dan data mungkin dikongsi dan peranti anda mungkin menjadi perlahan untuk sementara waktu."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Pentadbir IT anda meminta laporan pepijat untuk membantu menyelesaikan masalah peranti ini. Apl dan data mungkin dikongsi."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Proses ini mungkin memperlahankan peranti anda untuk sementara waktu"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"TERIMA"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"TOLAK"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Tukar papan kekunci"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Pilih papan kekunci"</string>
<string name="show_ime" msgid="2506087537466597099">"Pastikannya pada skrin, semasa papan kekunci fizikal aktif"</string>
@@ -1467,7 +1470,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Minta PIN sebelum menyahsemat"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Minta corak buka kunci sebelum menyahsemat"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Minta kata laluan sebelum menyahsemat"</string>
- <string name="dock_forced_resizable" msgid="5914261505436217520">"Apl mungkin tidak berfungsi dengan skrin terpisah."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Apl mungkin tidak berfungsi dengan skrin pisah."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Apl tidak menyokong skrin pisah."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Dipasang oleh pentadbir anda"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Dikemas kini oleh pentadbir anda"</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 5cf2bd3..c9f2ffc 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ထပ်မံရွေးချယ်စရာများအတွက် ထိပါ"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB အမှားစစ်ခြင်းအား ချိတ်ဆက်ထားသည်"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ဒီဘာဂင် ပိတ်ရန် ထိပါ။"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ချွတ်ယွင်းချက် အစီရင်ခံစာကို မျှဝေမလား။"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ချွတ်ယွင်းမှုအစီရင်ခံစာ မျှဝေနေသည်…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"ဤစက်ပစ္စည်းကို ပြဿနာအဖြေရှာရာတွင် ကူညီရန် သင့်အိုင်တီစီမံခန့်ခွဲသူသည် ချွတ်ယွင်းချက်အစီရင်ခံစာကို တောင်းဆိုထားသည်။ အက်ပ်များနှင့် ဒေတာကိုမျှဝေထားနိုင်ပြီး သင့်စက်ပစ္စည်းကို ခေတ္တနှေးကွေးသွားစေနိုင်သည်။"</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"ဤစက်ပစ္စည်းကို ပြဿနာအဖြေရှာရာတွင် ကူညီရန် သင့်အိုင်တီစီမံခန့်ခွဲသူသည် ချွတ်ယွင်းချက်အစီရင်ခံစာကို တောင်းဆိုထားသည်။ အက်ပ်များနှင့် ဒေတာကိုမျှဝေထားနိုင်ပါသည်။"</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"၎င်းသည်သင့်စက်ပစ္စည်းကို ခေတ္တနှေးကွေးသွားစေနိုင်သည်"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"လက်ခံပါ"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ငြင်းပယ်ပါ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"ကီးဘုတ် ပြောင်းလဲရန်"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"ကီးဘုတ်များကို ရွေးရန်"</string>
<string name="show_ime" msgid="2506087537466597099">"စက်၏ကီးဘုတ်ကိုအသုံးပြုနေစဉ် ၎င်းကိုမျက်နှာပြင်ပေါ်တွင် ထားပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 7ed5518..4ff6608 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Trykk for å se flere alternativer."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-feilsøking tilkoblet"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Trykk for å slå av USB-feilsøking."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vil du dele feilrapporten?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deler feilrapporten …"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IT-administratoren har bedt om en feilrapport for å hjelpe med feilsøkingen på denne enheten. Appene og dataene kan bli delt. Dette kan midlertidig gjøre enheten din tregere."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IT-administratoren har bedt om en feilrapport for å hjelpe med feilsøkingen på denne enheten. Appene og dataene kan bli delt."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Dette kan midlertidig gjøre enheten din tregere"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"GODTA"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"AVSLÅ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Endre tastatur"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Velg tastatur"</string>
<string name="show_ime" msgid="2506087537466597099">"Ha den på skjermen mens det fysiske tastaturet er aktivt"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 6291551..80f1602 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -1058,13 +1058,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"थप विकल्पहरूका लागि छुनुहोस्।"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB डिबग गर्ने जडित छ"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB डिबग गर्ने असक्षम पार्न छुनुहोस्।"</string>
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"बग रिपोर्ट लिँदै..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग रिपोर्टलाई साझेदारी गर्ने हो?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"बग रिपोर्टलाई साझेदारी गर्दै ..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"तपाईंको IT प्रशासकले यो यन्त्रको समस्या निवारण गर्नमा मद्दत गर्न बग रिपोर्टहरूका लागि अनुरोध गर्नु भएको छ । अनुप्रयोगहरू र डेटा साझेदारी गर्न सकिन्छ र तपाईंको यन्त्र अस्थायी रूपमा सुस्त हुन सक्छ।"</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"तपाईंको IT प्रशासकले यो यन्त्रको समस्या निवारण गर्नमा मदत गर्न बग रिपोर्टहरूका लागि अनुरोध गर्नु भएको छ । Apps र डेटा साझेदारी गर्न सक्नुहुन्छ ।"</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"यसले अस्थायी रूपमा तपाईंको यन्त्रलाई सुस्त बनाउन सक्छ"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"स्वीकार गर्नुहोस्"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"अस्वीकार गर्नुहोस्"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"तपाईँको IT प्रशासकले यस यन्त्रको समस्या निवारण गर्नमा मद्दत गर्न बग रिपोर्टका लागि अनुरोध गर्नुभएको छ। अनुप्रयोग र डेटा साझेदारी हुन सक्छ।"</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"साझेदारी गर्नुहोस्"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"अस्वीकार गर्नुहोस्"</string>
<string name="select_input_method" msgid="8547250819326693584">"कुञ्जीपाटी परिवर्तन गर्नुहोस्"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"कीबोर्ड छान्नुहोस्"</string>
<string name="show_ime" msgid="2506087537466597099">"भौतिक किबोर्ड सक्रिय हुँदा यसलाई स्क्रिनमा राख्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 404fdb4..06b63b9 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Tik voor meer opties."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-foutopsporing verbonden"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Tik om USB-foutopsporing uit te schakelen."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Bugrapport delen?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Bugrapport delen…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Je IT-beheerder heeft een bugrapport aangevraagd om problemen met dit apparaat op te lossen. Apps en gegevens kunnen worden gedeeld en je apparaat kan hierdoor tijdelijk worden vertraagd."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Je IT-beheerder heeft een bugrapport aangevraagd om problemen met dit apparaat op te lossen. Apps en gegevens kunnen worden gedeeld."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Dit kan je apparaat tijdelijk vertragen"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTEREN"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"WEIGEREN"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Toetsenbord wijzigen"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Toetsenborden kiezen"</string>
<string name="show_ime" msgid="2506087537466597099">"Dit op het scherm weergeven terwijl het fysieke toetsenbord actief is"</string>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index fa181da..89d2df8 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਸਪਰਸ਼ ਕਰੋ।"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ਡੀਬਗਿੰਗ ਕਨੈਕਟ ਕੀਤੀ"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ਡੀਬਗਿੰਗ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਉਣ ਲਈ ਛੋਹਵੋ।"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ਕੀ ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕਰਨੀ ਹੈ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"ਤੁਹਾਡੇ IT ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਇਸ ਡੀਵਾਈਸ ਦੀ ਸਮੱਸਿਆ ਨੂੰ ਠੀਕ ਕਰਨ ਵਿੱਚ ਮਦਦ ਲਈ ਬੱਗ ਰਿਪੋਰਟ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਹੈ। ਐਪਾਂ ਅਤੇ ਡੈਟੇ ਨੂੰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ ਅਤੇ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਆਰਜ਼ੀ ਤੌਰ \'ਤੇ ਹੌਲੀ ਹੋ ਸਕਦੀ ਹੈ।"</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"ਤੁਹਾਡੇ IT ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਇਸ ਡੀਵਾਈਸ ਦੀ ਸਮੱਸਿਆ ਨੂੰ ਠੀਕ ਕਰਨ ਵਿੱੱਚ ਮਦਦ ਲਈ ਬੱਗ ਰਿਪੋਰਟ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਹੈ। ਐਪਾਂ ਅਤੇ ਡੈਟੇ ਨੂੰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ।"</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"ਇਹ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਨੂੰ ਆਰਜ਼ੀ ਤੌਰ \'ਤੇ ਹੌਲੀ ਕਰ ਸਕਦਾ ਹੈ"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ਸਵੀਕਾਰ ਕਰੋ"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"ਕੀਬੋਰਡ ਬਦਲੋ"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"ਕੀਬੋਰਡਸ ਚੁਣੋ"</string>
<string name="show_ime" msgid="2506087537466597099">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ ਸਰਗਰਮ ਹੋਣ ਦੌਰਾਨ ਇਸ ਨੂੰ ਸਕ੍ਰੀਨ \'ਤੇ ਬਣਾਈ ਰੱਖੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index d1441bd..773cc88 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1068,13 +1068,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Kliknij, by zobaczyć więcej opcji."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Podłączono moduł debugowania USB"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dotknij, aby wyłączyć debugowanie USB."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Udostępnić raport o błędzie?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Udostępniam raport o błędzie…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Administrator poprosił o raport o błędzie, by szybciej rozwiązać problemy na tym urządzeniu. Raport może zawierać informacje o aplikacjach i inne dane. Urządzenie może przez chwilę działać wolniej."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Administrator poprosił o raport o błędzie, który pomoże w rozwiązaniu problemów na tym urządzeniu. Mogą zostać udostępnione aplikacje i dane."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Urządzenie może przez chwilę działać wolniej"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"AKCEPTUJ"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODRZUĆ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Zmień klawiaturę"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Wybierz klawiatury"</string>
<string name="show_ime" msgid="2506087537466597099">"Pozostaw na ekranie, gdy aktywna jest klawiatura fizyczna"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index b444e0a..2e55c37 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -243,7 +243,7 @@
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Agenda"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"acesse sua agenda"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
- <string name="permgroupdesc_sms" msgid="4656988620100940350">"enviar e ver mensagens SMS"</string>
+ <string name="permgroupdesc_sms" msgid="4656988620100940350">"envie e veja mensagens SMS"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Armazenamento"</string>
<string name="permgroupdesc_storage" msgid="637758554581589203">"acesse fotos, mídia e arquivos do dispositivo"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Microfone"</string>
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toque para ver mais opções."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB conectada"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toque para desativar a depuração do USB."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Compartilhar relatório do bug?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartilhando relatório do bug…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Seu administrador de TI solicitou um relatório de bug para ajudar a resolver problemas deste dispositivo. É possível que apps e dados sejam compartilhados, o que pode deixar seu dispositivo temporariamente mais lento."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Seu administrador de TI solicitou um relatório de bug para ajudar a resolver problemas deste dispositivo. É possível que apps e dados sejam compartilhados."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Isso pode deixar seu dispositivo temporariamente mais lento"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEITAR"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECUSAR"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Escolher teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manter na tela enquanto o teclado físico estiver ativo"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 4a5b0054..548ef45 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toque para ver mais opções."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB ligada"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toque para desat. a depuração USB."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Pretende partilhar o relatório de erro?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"A partilhar relatório de erro…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"O seu administrador de TI solicitou um relatório de erro para ajudar na resolução de problemas deste dispositivo. As aplicações e os dados podem ser partilhados e o dispositivo pode tornar-se temporariamente mais lento."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"O seu administrador de TI solicitou um relatório de erro para ajudar na resolução de problemas deste dispositivo. As aplicações e os dados podem ser partilhados."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Esta ação pode tornar o dispositivo mais lento temporariamente"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEITAR"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECUSAR"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Escolher teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manter no ecrã enquanto o teclado físico estiver ativo"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index b444e0a..2e55c37 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -243,7 +243,7 @@
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Agenda"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"acesse sua agenda"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
- <string name="permgroupdesc_sms" msgid="4656988620100940350">"enviar e ver mensagens SMS"</string>
+ <string name="permgroupdesc_sms" msgid="4656988620100940350">"envie e veja mensagens SMS"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Armazenamento"</string>
<string name="permgroupdesc_storage" msgid="637758554581589203">"acesse fotos, mídia e arquivos do dispositivo"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Microfone"</string>
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toque para ver mais opções."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB conectada"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toque para desativar a depuração do USB."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Compartilhar relatório do bug?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartilhando relatório do bug…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Seu administrador de TI solicitou um relatório de bug para ajudar a resolver problemas deste dispositivo. É possível que apps e dados sejam compartilhados, o que pode deixar seu dispositivo temporariamente mais lento."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Seu administrador de TI solicitou um relatório de bug para ajudar a resolver problemas deste dispositivo. É possível que apps e dados sejam compartilhados."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Isso pode deixar seu dispositivo temporariamente mais lento"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEITAR"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECUSAR"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Escolher teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manter na tela enquanto o teclado físico estiver ativo"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index a89f1b3..57be99c0 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1060,13 +1060,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Atingeți pentru mai multe opțiuni."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depanarea USB este conectată"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Atingeți pentru a dezactiva depanarea USB."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Trimiteți raportul de eroare?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Se trimite raportul de eroare…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Administratorul IT a solicitat un raport de eroare pentru a remedia problemele acestui dispozitiv. Este posibil să se permită accesul la date și aplicații, iar funcționarea dispozitivului poate fi încetinită temporar."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Administratorul IT a solicitat un raport de eroare pentru a remedia problemele acestui dispozitiv. Este posibil să se permită accesul la date și aplicații."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Acest proces poate încetini temporar funcționarea dispozitivului"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTAȚI"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REFUZAȚI"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Schimbați tastatura"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Alegeți tastaturi"</string>
<string name="show_ime" msgid="2506087537466597099">"Se păstrează pe ecran cât timp este activată tastatura fizică"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 85cbdc4..291f53e 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1068,13 +1068,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Нажмите, чтобы настроить."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Отладка по USB разрешена"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Нажмите, чтобы отключить отладку по USB."</string>
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Подготовка отчета об ошибке"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Разрешить доступ к информации об ошибке?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Отправка отчета об ошибке"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Администратор запросил отчет об ошибке, чтобы устранить неполадку. Он может получить доступ к приложениям и данным. Возможно временное снижение скорости работы вашего устройства."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Администратор запросил отчет об ошибке, чтобы устранить неполадку. Он может получить доступ к приложениям и данным."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Скорость работы устройства может быть временно снижена."</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИНЯТЬ"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ОТКЛОНИТЬ"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Администратор запросил отчет об ошибке, чтобы устранить неполадку. Он может получить доступ к приложениям и данным."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ПРЕДОСТАВИТЬ ДОСТУП"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОТКЛОНИТЬ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Выбор раскладки"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Выбрать раскладку"</string>
<string name="show_ime" msgid="2506087537466597099">"Показывать на экране, когда физическая клавиатура включена"</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index f37eb58..a44933f 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -1054,13 +1054,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"වඩා වැඩි විකල්ප සඳහා ස්පර්ශ කරන්න."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB නිදොස්කරණය සම්බන්ධිතයි"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB නිදොස්කරණය අබල කිරීමට ස්පර්ශ කරන්න."</string>
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"දෝෂ වාර්තාවක් ගනිමින්…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"දෝෂ වාර්තාව බෙදා ගන්නද?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"දෝෂ වාර්තාවක් බෙදා ගනිමින්..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"මෙම උපාංගය දෝෂාවේක්ෂණය සඳහා උදවු කිරීමට ඔබේ IT පරිපාලක දෝෂ වාර්තාවක් ඉල්ලා ඇත. යෙදුම් සහ දත්ත බෙදා ගත හැකි අතර ඔබේ උපාංගය තාවකාලිකව මන්දගාමී විය හැකිය."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"මෙම උපාංගය දෝෂාවේක්ෂණය සඳහා උදවු කිරීමට ඔබේ IT පරිපාලක දෝෂ වාර්තාවක් ඉල්ලා ඇත. යෙදුම් සහ දත්ත බෙදා ගත හැකිය."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"මෙය ඔබේ උපාංගය තාවකාලිකව මන්දගාමී කළ හැකිය"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"පිළිගන්න"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ප්රතික්ෂේප කරන්න"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"මෙම උපාංගය දෝෂාවේක්ෂණය සඳහා උදවු කිරීමට ඔබේ IT පරිපාලක දෝෂ වාර්තාවක් ඉල්ලා ඇත. යෙදුම් සහ දත්ත බෙදා ගත හැකිය."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"බෙදා ගන්න"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ප්රතික්ෂේප කරන්න"</string>
<string name="select_input_method" msgid="8547250819326693584">"යතුරු පුවරු වෙනස් කිරීම"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"යතුරු පුවරු තෝරන්න"</string>
<string name="show_ime" msgid="2506087537466597099">"භෞතික යතුරු පුවරුව සක්රිය අතරතුර එය තිරය මත තබා ගන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index ddb162a..80a4293 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1068,13 +1068,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Ďalšie možnosti zobrazíte klepnutím."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Ladenie cez USB pripojené"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Klepnutím zakážete ladenie cez USB"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Chcete zdieľať hlásenie chyby?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Zdieľa sa hlásenie chyby…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Správca IT si vyžiadal hlásenie chyby, aby mohol vyriešiť problém na tomto zariadení. Aplikácie a dáta môžu byť zdieľané. Môže to dočasne spomaliť vaše zariadenie."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Správca IT si vyžiadal hlásenie chyby, aby mohol vyriešiť problém na tomto zariadení. Aplikácie a dáta môžu byť zdieľané."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Môže to dočasne spomaliť vaše zariadenie."</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRIJAŤ"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODMIETNUŤ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Zmeniť klávesnicu"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Vybrať klávesnicu"</string>
<string name="show_ime" msgid="2506087537466597099">"Ponechať na obrazovke, keď je aktívna fyzická klávesnica"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 47330fb..5e85770 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1068,13 +1068,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Za več možnosti se dotaknite."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Iskanje in odpravljanje napak USB je povezano"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dotaknite se, če želite onemogočiti iskanje in odpravljanje napak prek vrat USB."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Želite poslati poročilo o napakah?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Pošiljanje poročila o napakah …"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Skrbnik za IT je zahteval poročilo o napakah za pomoč pri odpravljanju napak v tej napravi. Aplikacije in podatki bodo morda dani v skupno rabo in delovanje naprave bo morda začasno upočasnjeno."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Skrbnik za IT je zahteval poročilo o napakah za pomoč pri odpravljanju napak v tej napravi. Aplikacije in podatki bodo morda dani v skupno rabo."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"To bo morda začasno upočasnilo delovanje naprave"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"SPREJMEM"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"NE SPREJMEM"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Sprememba tipkovnice"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Izbira tipkovnic"</string>
<string name="show_ime" msgid="2506087537466597099">"Ohrani na zaslonu, dokler je aktivna fizična tipkovnica"</string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index db46b89..9c9268b 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Prek për më shumë opsione."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Korrigjuesi i USB-së i lidhur"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Prek për të çaktivizuar korrigjimin e gabimeve të USB-së."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Të ndahet raporti i defektit në kod?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Po ndan raportin e defekteve në kod..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Administratori i teknologjisë së informacionit kërkoi një raport të defekteve në kod për të ndihmuar me zgjidhjen e problemeve. Aplikacioni dhe të dhënat mund të ndahen dhe kjo mund të ngadalësojë përkohësisht pajisjen tënde."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Administratori i teknologjisë së informacionit kërkoi një raport të defekteve në kod për të ndihmuar me zgjidhjen e problemeve. Aplikacioni dhe të dhënat mund të ndahen."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Kjo mund të ngadalësojë përkohësisht pajisjen tënde"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRANO"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REFUZO"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Ndërro tastierë"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Zgjidh tastierat"</string>
<string name="show_ime" msgid="2506087537466597099">"Mbaje në ekran ndërsa tastiera fizike është aktive"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index d1ac852..528832f 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -163,7 +163,7 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Превише <xliff:g id="CONTENT_TYPE">%s</xliff:g> избрисаних ставки."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Меморија таблета је пуна! Избришите неке датотеке да бисте ослободили простор."</string>
<string name="low_memory" product="watch" msgid="4415914910770005166">"Меморија сата је пуна. Избришите неке датотеке да бисте ослободили простор."</string>
- <string name="low_memory" product="tv" msgid="516619861191025923">"Складишни простор на ТВ-у је попуњен. Избришите неке датотеке да бисте ослободили простор."</string>
+ <string name="low_memory" product="tv" msgid="516619861191025923">"Меморијски простор на ТВ-у је попуњен. Избришите неке датотеке да бисте ослободили простор."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Складиште телефона је пуно! Избришите неке датотеке како бисте ослободили простор."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мрежа се можда надгледа"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Од стране непознате треће стране"</string>
@@ -312,7 +312,7 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Дозвољава апликацији да учини сопствене компоненте трајним у меморији. Ово може да ограничи меморију доступну другим апликацијама и успори таблет."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Дозвољава апликацији да неке своје делове трајно задржи у меморији. То може да ограничи меморију доступну другим апликацијама и успори ТВ."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Дозвољава апликацији да учини сопствене компоненте трајним у меморији. Ово може да ограничи меморију доступну другим апликацијама и успори телефон."</string>
- <string name="permlab_getPackageSize" msgid="7472921768357981986">"мерење простора за складиштење у апликацији"</string>
+ <string name="permlab_getPackageSize" msgid="7472921768357981986">"мерење меморијског простора у апликацији"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Дозвољава апликацији да преузме величине кôда, података и кеша."</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"измена подешавања система"</string>
<string name="permdesc_writeSettings" msgid="7775723441558907181">"Дозвољава апликацији да мења податке о подешавању система. Злонамерне апликације могу да оштете конфигурацију система."</string>
@@ -885,9 +885,9 @@
<string name="deleteText" msgid="6979668428458199034">"Избриши"</string>
<string name="inputMethod" msgid="1653630062304567879">"Метод уноса"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Радње у вези са текстом"</string>
- <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Простор за складиштење је на измаку"</string>
+ <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Меморијски простор је на измаку"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Неке системске функције можда не функционишу"</string>
- <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Нема довољно складишног простора за систем. Уверите се да имате 250 MB слободног простора и поново покрените."</string>
+ <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Нема довољно меморијског простора за систем. Уверите се да имате 250 MB слободног простора и поново покрените."</string>
<string name="app_running_notification_title" msgid="8718335121060787914">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је покренута"</string>
<string name="app_running_notification_text" msgid="4653586947747330058">"Додирните за више информација или заустављање апликације."</string>
<string name="ok" msgid="5970060430562524910">"Потврди"</string>
@@ -1060,13 +1060,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Додирните за још опција."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Отклањање грешака са USB-а је успостављено"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Додирните да бисте онемогућили отклањање грешака са USB-а."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Желите ли да поделите извештај о грешци?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Дели се извештај о грешци…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"ИТ администратор је затражио извештај о грешци ради лакшег решавања проблема у вези са овим уређајем. Апликације и подаци могу да се деле, а уређај ће се привремено успорити."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"ИТ администратор је затражио извештај о грешци ради лакшег решавања проблема у вези са овим уређајем. Апликације и подаци могу да се деле."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Ово ће привремено успорити уређај"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИХВАТИ"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ОДБИЈ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Промените тастатуру"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Изаберите тастатуре"</string>
<string name="show_ime" msgid="2506087537466597099">"Задржи га на екрану док је физичка тастатура активна"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index ab61097..daa767a 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Visa fler alternativ genom att trycka."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-felsökning ansluten"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Tryck om du vill inaktivera USB-felsökning."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vill du dela felrapporten?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Felrapporten delas …"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IT-administratören har bett om en felrapport som hjälp vid felsökningen av den här enheten. Appar och data kan komma att delas. Detta kan tillfälligt göra enheten långsammare."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IT-administratören har bett om en felrapport som hjälp vid felsökningen av den här enheten. Appar och data kan komma att delas."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Detta kan tillfälligt göra enheten långsammare"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"GODKÄNN"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"AVVISA"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Byt tangentbord"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Välj tangentbord"</string>
<string name="show_ime" msgid="2506087537466597099">"Ha kvar den på skärmen när det fysiska tangentbordet används"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 271c48d..d807aac 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1054,13 +1054,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Gusa kwa chaguo zaidi."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Utatuaji wa USB umeunganishwa"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Gusa ili uzime utatuaji wa USB."</string>
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Inatayarisha ripoti ya hitilafu…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Ungependa kushiriki ripoti ya hitilafu?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Inashiriki ripoti ya hitilafu…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Msimamizi wako wa Teknolojia ya Habari ameomba ripoti ya hitilafu ili kusaidia katika utatuzi wa kifaa hiki. Huenda hatua hii ikasababisha programu na data kushirikiwa na kupunguza kasi ya kifaa chako kwa muda."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Msimamizi wako wa TEHAMA ameomba ripoti ya hitilafu ili kusaidia katika utatuzi wa hitilafu kwenye kifaa hiki. Programu na data zinaweza kushirikiwa."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Hatua hii inaweza kupunguza kasi ya kifaa chako kwa muda"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"KUBALI"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"KATAA"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Msimamizi wako wa TEHAMA ameomba ripoti ya hitilafu ili kusaidia katika utatuzi wa hitilafu kwenye kifaa hiki. Programu na data zinaweza kushirikiwa."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHIRIKI"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"KATAA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Badilisha kibodi"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Chagua kibodi"</string>
<string name="show_ime" msgid="2506087537466597099">"Iweke kwenye skrini wakati kibodi inapotumika"</string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index f49c1b5..40011d2 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"கூடுதல் விருப்பங்களுக்காகத் தொடவும்."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB பிழைதிருத்தம் இணைக்கப்பட்டது"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB பிழைத்திருத்தத்தை முடக்க, தொடவும்."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"பிழை அறிக்கையைப் பகிரவா?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"பிழை அறிக்கையைப் பகிர்கிறது…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"இந்தச் சாதனத்தின் பிழைகாண்பதற்கு உதவ, உங்கள் ஐடி நிர்வாகி பிழை அறிக்கையைக் கோரியுள்ளார். பயன்பாடுகளும் தரவும் பகிரப்படலாம். தற்காலிகமாக சாதனத்தின் வேகம் குறையலாம்."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"இந்தச் சாதனத்தின் பிழைகாண்பதற்கு உதவ, உங்கள் ஐடி நிர்வாகி பிழை அறிக்கையைக் கோரியுள்ளார். பயன்பாடுகளும் தரவும் பகிரப்படலாம்."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"இது தற்காலிகமாக சாதனத்தின் வேகத்தைக் குறைக்கலாம்"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"சரி"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"வேண்டாம்"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"விசைப்பலகையை மாற்று"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"விசைப்பலகைகளைத் தேர்வுசெய்க"</string>
<string name="show_ime" msgid="2506087537466597099">"கைமுறை விசைப்பலகை இயக்கத்தில் இருக்கும் போது IMEஐ திரையில் வைத்திரு"</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 8047621..22aa04d 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"మరిన్ని ఎంపికల కోసం తాకండి."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB డీబగ్గింగ్ కనెక్ట్ చేయబడింది"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB డీబగ్గింగ్ను నిలిపివేయడానికి తాకండి."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"బగ్ నివేదికను భాగస్వామ్యం చేయాలా?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"బగ్ నివేదికను భాగస్వామ్యం చేస్తోంది..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"మీ ఐటి నిర్వాహకులు ఈ పరికరం సమస్యకు పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ నివేదికను అభ్యర్థించారు. అనువర్తనాలు మరియు డేటా భాగస్వామ్యం చేయబడవచ్చు మరియు మీ పరికరం పనితీరు తాత్కాలికంగా నెమ్మదించవచ్చు."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"మీ ఐటి నిర్వాహకులు ఈ పరికరం సమస్యకు పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ నివేదికను అభ్యర్థించారు. అనువర్తనాలు మరియు డేటా భాగస్వామ్యం చేయబడవచ్చు."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"దీని వల్ల మీ పరికరం పనితీరు తాత్కాలికంగా నెమ్మదించవచ్చు"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ఆమోదిస్తున్నాను"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"తిరస్కరిస్తున్నాను"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"కీబోర్డ్ను మార్చు"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"కీబోర్డ్లను ఎంచుకోండి"</string>
<string name="show_ime" msgid="2506087537466597099">"దీన్ని భౌతిక కీబోర్డ్ సక్రియంగా ఉన్నప్పుడు స్క్రీన్పై ఉంచుతుంది"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 114b31b..2e6f62e 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"แตะเพื่อดูตัวเลือกเพิ่มเติม"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"เชื่อมต่อการแก้ไขข้อบกพร่อง USB แล้ว"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"แตะเพื่อปิดใช้งานการแก้ไขข้อบกพร่อง USB"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"แชร์รายงานข้อบกพร่องไหม"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"กำลังแชร์รายงานข้อบกพร่อง…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"ผู้ดูแลระบบไอทีของคุณขอรายงานข้อบกพร่องเพื่อช่วยในการแก้ปัญหาอุปกรณ์นี้ อาจมีการแชร์แอปและข้อมูล ซึ่งอาจทำให้อุปกรณ์ทำงานช้าลงชั่วคราว"</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"ผู้ดูแลระบบไอทีของคุณขอรายงานข้อบกพร่องเพื่อช่วยในการแก้ปัญหาอุปกรณ์นี้ อาจมีการแชร์แอปและข้อมูล"</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"การดำเนินการนี้อาจทำให้อุปกรณ์ทำงานช้าลงชั่วคราว"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ยอมรับ"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ปฏิเสธ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"เปลี่ยนแป้นพิมพ์"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"เลือกแป้นพิมพ์"</string>
<string name="show_ime" msgid="2506087537466597099">"เปิดทิ้งไว้บนหน้าจอในระหว่างใช้งานแป้นพิมพ์จริง"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 1e2a606..71c3460 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Pindutin para sa higit pang mga opsyon."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Konektado ang debugging ng USB"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Pindutin upang i-disable ang pagde-debug ng USB."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Gusto mo bang ibahagi ang ulat ng bug?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Ibinabahagi ang ulat ng bug…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Humiling ang iyong IT admin ng isang ulat ng bug upang makatulong sa pag-troubleshoot sa device na ito. Maaaring ibahagi ang mga app at data at maaaring pansamantalang bumagal ang iyong device."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Humiling ang iyong IT admin ng isang ulat ng bug upang makatulong sa pag-troubleshoot sa device na ito. Maaaring ibahagi ang mga app at data."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Maaaring pansamantalang bumagal ang iyong device dahil dito"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"TANGGAPIN"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"TANGGIHAN"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Baguhin ang keyboard"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Pumili ng mga keyboard"</string>
<string name="show_ime" msgid="2506087537466597099">"Panatilihin ito sa screen habang aktibo ang pisikal na keyboard"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index ab0781b..c60983b 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Daha fazla seçenek için dokunun."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB hata ayıklaması bağlandı"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB hata ayıklama özelliğini devre dışı bırakmak için dokunun."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Hata raporu paylaşılsın mı?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Hata raporu paylaşılıyor..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"BT yöneticiniz, bu cihazda sorun gidermeye yardımcı olması için bir hata raporu istedi. Uygulamalar ve veriler paylaşılabilir. Bu durum, cihazınızı geçici olarak yavaşlatabilir."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"BT yöneticiniz, bu cihazda sorun gidermeye yardımcı olması için bir hata raporu istedi. Uygulamalar ve veriler paylaşılabilir."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Bu durum, cihazınızı geçici olarak yavaşlatabilir"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"KABUL ET"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REDDET"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Klavyeyi değiştir"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Klavyeyi seç"</string>
<string name="show_ime" msgid="2506087537466597099">"Fiziksel klavye etkin durumdayken ekranda tut"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 439d68f..ed0a978 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1068,13 +1068,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Торкніться, щоб побачити більше опцій."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Налагодження USB завершено"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Торкніться, щоб вимкнути налагодження USB."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Надіслати звіт про помилку?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Надсилається звіт про помилку…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Ваш IT-адміністратор просить надіслати повідомлення про помилку, щоб вирішити проблему з пристроєм. Він може отримати доступ до ваших додатків і даних. Це також може тимчасово сповільнити роботу вашого пристрою."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Ваш IT-адміністратор просить надіслати повідомлення про помилку, щоб вирішити проблему з пристроєм. Він може отримати доступ до ваших додатків і даних."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Це може тимчасово сповільнити роботу вашого пристрою"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИЙНЯТИ"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ВІДХИЛИТИ"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Змінити клавіатуру"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Вибрати клавіатури"</string>
<string name="show_ime" msgid="2506087537466597099">"Утримуйте на екрані, коли активна фізична клавіатура"</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index 1bf224b..d314025 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"مزید اختیارات کیلئے ٹچ کریں۔"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ڈیبگ کرنا مربوط ہو گیا"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ڈیبگنگ کو غیر فعال کرنے کیلئے ٹچ کریں۔"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"بگ رپورٹ کا اشتراک کریں؟"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"بگ رپورٹ کا اشتراک ہو رہا ہے…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"آپ کے IT منتظم نے اس آلہ کا مسئلہ حل کرنے میں مدد کیلئے ایک بگ رپورٹ کی درخواست کی ہے۔ ایپس اور ڈیٹا کا اشتراک ہو سکتا ہے اور آپ کا آلہ عارضی طور پر سست ہو سکتا ہے۔"</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"آپ کے IT منتظم نے اس آلہ کا مسئلہ حل کرنے میں مدد کیلئے ایک بگ رپورٹ کی درخواست کی ہے۔ ایپس اور ڈیٹا کا اشتراک ہو سکتا ہے۔"</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"اس سے آپ کا آلہ عارضی طور پر سست ہو سکتا ہے"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"قبول کریں"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"مسترد کریں"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"کی بورڈ تبدیل کریں"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"کی بورڈز منتخب کریں"</string>
<string name="show_ime" msgid="2506087537466597099">"جب فزیکل کی بورڈ فعال ہو تو IME کو اسکرین پر رکھیں"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index d862036..8da4e41 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -895,7 +895,7 @@
<string name="whichApplication" msgid="4533185947064773386">"Ilovani tanlang"</string>
<string name="whichApplicationNamed" msgid="8260158865936942783">"“%1$s” bilan ochish"</string>
<string name="whichViewApplication" msgid="3272778576700572102">"Ochish…"</string>
- <string name="whichViewApplicationNamed" msgid="2286418824011249620">"“%1$s” yordamida ochish"</string>
+ <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s bilan ochish"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Tahrirlash…"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"“%1$s” yordamida tahrirlash"</string>
<string name="whichSendApplication" msgid="6902512414057341668">"Ulashish…"</string>
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Sozlash uchun bosing."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB orqali nosozliklarni tuzatish"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"O‘chirib qo‘yish uchun bosing."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Xatoliklar hisoboti yuborilsinmi?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Xatoliklar hisoboti yuborilmoqda…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Administratoringiz bu qurilma nosozliklarini tuzatish uchun xatoliklar hisobotini so‘ramoqda. Ilova va ma’lumotlardan foydalanilishi va bu vaqtincha qurilmangizni sekinlashtirishi ham mumkin."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Administratoringiz bu qurilma nosozliklarini tuzatish uchun xatoliklar hisobotini so‘ramoqda. Ilova va ma’lumotlardan foydalanilishi mumkin."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Qurilmaning ishlash tezligi vaqtincha pasayishi mumkin."</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"QABUL QILISH"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RAD ETISH"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Klaviaturani o‘zgartirish"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Klaviaturani tanlash"</string>
<string name="show_ime" msgid="2506087537466597099">"Tashqi klaviaturadan foydalanilayotganda buni ekranda saqlab turish"</string>
@@ -1505,7 +1508,7 @@
<item quantity="other">%d soat</item>
<item quantity="one">1 soat</item>
</plurals>
- <string name="zen_mode_until" msgid="7336308492289875088">"Ushbu vaqtgacha: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
+ <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> gacha"</string>
<string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> gacha (keyingi signal)"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Men o‘chirmaguncha"</string>
<string name="zen_mode_forever_dnd" msgid="3792132696572189081">"“Bezovta qilinmasin” rejimi o‘chirilmaguncha"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index af69c31..3dcab7d 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1052,13 +1052,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Chạm để có các tùy chọn khác."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Gỡ lỗi USB đã được kết nối"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Chạm để vô hiệu hóa gỡ lỗi USB."</string>
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Đang thu thập báo cáo lỗi…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Chia sẻ báo cáo lỗi?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Đang chia sẻ báo cáo lỗi…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Quản trị viên CNTT của bạn đã yêu cầu báo cáo lỗi để giúp khắc phục sự cố thiết bị này. Bạn có thể chia sẻ ứng dụng, đồng thời dữ liệu và thiết bị của bạn tạm thời có thể bị chậm."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Quản trị viên CNTT của bạn đã yêu cầu báo cáo lỗi để giúp khắc phục sự cố thiết bị này. Bạn có thể chia sẻ ứng dụng và dữ liệu."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Tác vụ này tạm thời có thể làm chậm thiết bị của bạn"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"CHẤP NHẬN"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"TỪ CHỐI"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Quản trị viên CNTT của bạn đã yêu cầu báo cáo lỗi để giúp khắc phục sự cố thiết bị này. Bạn có thể chia sẻ ứng dụng và dữ liệu."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"CHIA SẺ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"TỪ CHỐI"</string>
<string name="select_input_method" msgid="8547250819326693584">"Thay đổi bàn phím"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Chọn bàn phím"</string>
<string name="show_ime" msgid="2506087537466597099">"Tiếp tục sử dụng ứng dụng trên màn hình trong khi bàn phím thực đang hoạt động"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 85616b1..58d385d 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"触摸以查看更多选项。"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"已连接到USB调试"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"触摸可停用USB调试。"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享错误报告吗?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享错误报告…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"您的 IT 管理员希望获取错误报告,以便排查此设备的问题。报告可能会透露您设备上的应用和数据,设备运行速度也可能会因此而暂时减慢。"</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"您的 IT 管理员希望获取错误报告,以便排查此设备的问题。报告可能会透露您设备上的应用和数据。"</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"这可能会暂时减慢您设备的运行速度"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"接受"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"拒绝"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"更改键盘"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"选择键盘"</string>
<string name="show_ime" msgid="2506087537466597099">"连接到实体键盘时使其在屏幕上保持显示状态"</string>
@@ -1467,7 +1470,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消时要求输入PIN码"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"取消时要求绘制解锁图案"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"取消时要求输入密码"</string>
- <string name="dock_forced_resizable" msgid="5914261505436217520">"应用可能无法在分屏模式下运行。"</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"应用可能无法在分屏模式下正常运行。"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"应用不支持分屏。"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"已由管理员安装"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"由您单位的管理员更新"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 4c46574..faa320d 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1052,13 +1052,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"輕觸以瀏覽更多選項。"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"已連接 USB 偵錯工具"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"輕觸即可停用 USB 偵錯。"</string>
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"正在取得錯誤報告…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享錯誤報告嗎?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享錯誤報告…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"您的 IT 管理員要求您提供錯誤報告,以協助解決此裝置的問題。報告可能包含應用程式和相關資料,裝置的運作速度也可能暫時減慢。"</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"您的 IT 管理員要求您提供錯誤報告,以協助解決此裝置的問題。報告可能會披露裝置中的應用程式和相關資料。"</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"裝置的運作速度可能因而減慢"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"接受"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"拒絕"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"您的 IT 管理員要求您提供錯誤報告,以協助解決此裝置的問題。報告可能包含應用程式和相關資料。"</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"分享"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"拒絕"</string>
<string name="select_input_method" msgid="8547250819326693584">"變更鍵盤"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"選擇鍵盤"</string>
<string name="show_ime" msgid="2506087537466597099">"在實體鍵盤處於連接狀態時保持顯示"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 7db8794..d6820db 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"輕觸即可顯示更多選項。"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"已連接 USB 偵錯工具"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"輕觸即可停用 USB 偵錯。"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享錯誤報告嗎?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享錯誤報告…"</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"您的 IT 管理員要求您提供錯誤報告,以便排解這個裝置發生的問題。報告可能會揭露裝置中的應用程式和相關資料,裝置運行速度也可能會因此暫時減慢。"</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"您的 IT 管理員要求您提供錯誤報告,以便排解這個裝置發生的問題。報告可能會揭露裝置中的應用程式和相關資料。"</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"這可能會暫時減慢裝置運行速度"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"接受"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"拒絕"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"變更鍵盤"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"選擇鍵盤"</string>
<string name="show_ime" msgid="2506087537466597099">"有連接的實體鍵盤時保持顯示"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 9432024..ed5ec7d2 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1052,13 +1052,16 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Thinta ukuze uthole ezinye izinketho."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Ukulungisa iphutha le-USB kuxhunyiwe"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Thinta ukwenza ukuthi ukudibhaga kwe-USB kungasebenzi."</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Yabelana ngombiko wesiphazamisi?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Yabelana ngombiko wesiphazamisi..."</string>
- <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Umlawuli wakho we-IT ucele umbiko wesiphazamisi ukusiza ukuxazulula inkinga yale divayisi. Izinhlelo zokusebenza zingabelwana futhi idivayisi yakho ingahle yehle kancane."</string>
- <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Umqondisi wakho we-IT ucele umbiko wesiphazamisi ukukusiza ukuxazulula inkinga kule divayisi. Izinhlelo zokusebenza nedatha ingabiwa."</string>
- <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Lokhu kungahambisa kancane idivayisi yakho okwesikhashana"</string>
- <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"YAMUKELA"</string>
- <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"YENQABA"</string>
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
<string name="select_input_method" msgid="8547250819326693584">"Shintsha ikhibhodi"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Khetha amakhibhodi"</string>
<string name="show_ime" msgid="2506087537466597099">"Yigcine kusikrini ngenkathi kusebenza ikhibhodi ephathekayo"</string>
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..1d7034d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -548,9 +548,6 @@
[CHAR LIMIT=4] -->
<string name="status_bar_notification_info_overflow">999+</string>
- <!-- The number of notifications in the notification header. An example would be (2) or (12) -->
- <string name="notification_children_count_bracketed">(<xliff:g id="notificationCount" example="1">%d</xliff:g>)</string>
-
<!-- The divider symbol between different parts of the notification header. not translatable [CHAR LIMIT=1] -->
<string name="notification_header_divider_symbol" translatable="false">•</string>
@@ -2917,20 +2914,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 -->
@@ -3137,11 +3132,13 @@
<!-- Label to show for a service that is running because it is observing
the user's notifications. -->
<string name="notification_listener_binding_label">Notification listener</string>
+ <!-- Label to show for a service that is running because the system is in VR mode. -->
+ <string name="vr_listener_binding_label">VR listener</string>
<!-- Label to show for a service that is running because it is providing conditions. -->
<string name="condition_provider_service_binding_label">Condition provider</string>
<!-- Label to show for a service that is running because it is observing and modifying the
importance of the user's notifications. -->
- <string name="notification_assistant_binding_label">Notification assistant</string>
+ <string name="notification_ranker_binding_label">Notification ranker service</string>
<!-- Do Not Translate: Alternate eri.xml -->
<string name="alternate_eri_file">/data/eri.xml</string>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index a9c8a06..a65a813 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -993,8 +993,7 @@
</style>
<style name="Widget.Material.SuggestionItem" parent="@android:style/TextAppearance.Material.Body1">
- <item name="alpha">.87</item>
- <item name="textColor">@color/black</item>
+ <item name="textColor">#8a000000</item> <!-- alpha=.54, textColor=@color/black -->
<item name="drawablePadding">8dip</item>
<item name="gravity">start|center_vertical</item>
<item name="layout_gravity">start|center_vertical</item>
@@ -1009,12 +1008,11 @@
</style>
<style name="TextAppearance.Material.TextSuggestionHighlight" parent="Widget.Material.SuggestionItem">
- <item name="textColor">#009688</item>
+ <item name="textColor">#de000000</item> <!-- alpha=.87, textColor=@color/black -->
</style>
<style name="Widget.Material.SuggestionButton" parent="@android:style/TextAppearance.Material.Button">
- <item name="alpha">.87</item>
- <item name="textColor">#009688</item>
+ <item name="textColor">#de009688</item> <!-- alpha=.87, textColor=#009688 -->
<item name="drawablePadding">8dip</item>
<item name="gravity">start|center_vertical</item>
<item name="layout_gravity">start|center_vertical</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 44a7a8d..0120128 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" />
@@ -1841,8 +1842,9 @@
<java-symbol type="string" name="low_internal_storage_view_text_no_boot" />
<java-symbol type="string" name="low_internal_storage_view_title" />
<java-symbol type="string" name="notification_listener_binding_label" />
+ <java-symbol type="string" name="vr_listener_binding_label" />
<java-symbol type="string" name="condition_provider_service_binding_label" />
- <java-symbol type="string" name="notification_assistant_binding_label" />
+ <java-symbol type="string" name="notification_ranker_binding_label" />
<java-symbol type="string" name="report" />
<java-symbol type="string" name="select_input_method" />
<java-symbol type="string" name="select_keyboard_layout_notification_title" />
@@ -2390,6 +2392,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. -->
@@ -2403,11 +2406,9 @@
<java-symbol type="id" name="notification_material_reply_text_2" />
<java-symbol type="id" name="notification_material_reply_text_3" />
- <java-symbol type="string" name="notification_children_count_bracketed" />
<java-symbol type="string" name="notification_hidden_text" />
<java-symbol type="string" name="notification_hidden_by_policy_text" />
<java-symbol type="id" name="app_name_text" />
- <java-symbol type="id" name="number_of_children" />
<java-symbol type="id" name="header_sub_text" />
<java-symbol type="id" name="expand_button" />
<java-symbol type="id" name="notification_header" />
@@ -2431,8 +2432,9 @@
<java-symbol type="string" name="importance_from_person" />
<java-symbol type="layout" name="work_widget_mask_view" />
+ <java-symbol type="id" name="work_widget_mask_frame" />
<java-symbol type="id" name="work_widget_app_icon" />
- <java-symbol type="drawable" name="work_widget_mask_view_background" />
+ <java-symbol type="id" name="work_widget_badge_icon" />
<java-symbol type="id" name="aerr_report" />
<java-symbol type="id" name="aerr_reset" />
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index 8bf635e..478d66c 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -24,7 +24,6 @@
<item name="windowBackground">@color/black</item>
<item name="windowContentOverlay">@null</item>
<item name="windowIsFloating">false</item>
- <item name="windowSwipeToDismiss">true</item>
<!-- Required to force windowInsets dispatch through application UI. -->
<item name="windowOverscan">true</item>
</style>
@@ -42,7 +41,6 @@
<item name="windowBackground">@color/white</item>
<item name="windowContentOverlay">@null</item>
<item name="windowIsFloating">false</item>
- <item name="windowSwipeToDismiss">true</item>
<!-- Required to force windowInsets dispatch through application UI. -->
<item name="windowOverscan">true</item>
</style>
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/print/BasePrintTest.java b/core/tests/coretests/src/android/print/BasePrintTest.java
index 3feb0e9..c9bc8aa 100644
--- a/core/tests/coretests/src/android/print/BasePrintTest.java
+++ b/core/tests/coretests/src/android/print/BasePrintTest.java
@@ -61,7 +61,6 @@
public abstract class BasePrintTest extends InstrumentationTestCase {
private static final long OPERATION_TIMEOUT = 30000;
- private static final String PRINT_SPOOLER_PACKAGE_NAME = "com.android.printspooler";
private static final String PM_CLEAR_SUCCESS_OUTPUT = "Success";
private static final String COMMAND_LIST_ENABLED_IME_COMPONENTS = "ime list -s";
private static final String COMMAND_PREFIX_ENABLE_IME = "ime enable ";
@@ -249,8 +248,9 @@
protected void clearPrintSpoolerData() throws Exception {
assertTrue("failed to clear print spooler data",
runShellCommand(getInstrumentation(), String.format(
- "pm clear --user %d %s", CURRENT_USER_ID, PRINT_SPOOLER_PACKAGE_NAME))
- .contains(PM_CLEAR_SUCCESS_OUTPUT));
+ "pm clear --user %d %s", CURRENT_USER_ID,
+ PrintManager.PRINT_SPOOLER_PACKAGE_NAME))
+ .contains(PM_CLEAR_SUCCESS_OUTPUT));
}
@SuppressWarnings("unchecked")
diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
index 5179b42..cbf17a4 100644
--- a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
+++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
@@ -27,24 +27,9 @@
import android.os.Process;
import android.os.ServiceManager;
import android.os.UserHandle;
-import android.print.IPrintDocumentAdapter;
-import android.print.IPrintJobStateChangeListener;
-import android.print.IPrintManager;
-import android.print.IPrinterDiscoveryObserver;
-import android.print.PageRange;
-import android.print.PrintAttributes;
import android.print.PrintAttributes.Margins;
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
-import android.print.PrintDocumentAdapter;
-import android.print.PrintJob;
-import android.print.PrintJobId;
-import android.print.PrintJobInfo;
-import android.print.PrintManager;
-import android.print.PrinterCapabilitiesInfo;
-import android.print.PrinterDiscoverySession;
-import android.print.PrinterId;
-import android.print.PrinterInfo;
import android.printservice.PrintServiceInfo;
import android.print.mockservice.MockPrintService;
@@ -134,7 +119,7 @@
if (session.getPrinters().isEmpty()) {
final String PRINTER_NAME = "good printer";
- List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+ List<PrinterInfo> printers = new ArrayList<>();
// Add the printer.
mGoodPrinterId = session.getService()
@@ -184,6 +169,18 @@
}
/**
+ * Create a IPrintServicesChangeListener object.
+ *
+ * @return the object
+ * @throws Exception if the object could not be created.
+ */
+ private IPrintServicesChangeListener createMockIPrintServicesChangeListener() throws Exception {
+ return new PrintManager.PrintServicesChangeListenerWrapper(null,
+ new Handler(Looper.getMainLooper()));
+ }
+
+
+ /**
* Create a IPrinterDiscoveryObserver object.
*
* @return the object
@@ -193,6 +190,16 @@
return new PrinterDiscoverySession.PrinterDiscoveryObserver(null);
}
+ private void startPrinting() {
+ mGoodPrintJob = print(createMockAdapter(), null);
+
+ // Wait for PrintActivity to be ready
+ waitForStartAdapterCallbackCalled();
+
+ // Wait for printer discovery session to be ready
+ waitForPrinterDiscoverySessionStartCallbackCalled();
+ }
+
@Override
public void setUp() throws Exception {
super.setUp();
@@ -201,20 +208,12 @@
mGoodComponentName = getActivity().getComponentName();
- mGoodPrintJob = print(createMockAdapter(), null);
-
mIPrintManager = IPrintManager.Stub
.asInterface(ServiceManager.getService(Context.PRINT_SERVICE));
// Generate dummy printerId which is a valid PrinterId object, but does not correspond to a
// printer
mBadPrinterId = new PrinterId(mGoodComponentName, "dummy printer");
-
- // Wait for PrintActivity to be ready
- waitForStartAdapterCallbackCalled();
-
- // Wait for printer discovery session to be ready
- waitForPrinterDiscoverySessionStartCallbackCalled();
}
/**
@@ -222,11 +221,11 @@
*/
private interface Invokable {
/**
- * Execute the {@link Invokable}
+ * Execute the invokable
*
* @throws Exception
*/
- public void run() throws Exception;
+ void run() throws Exception;
}
/**
@@ -255,6 +254,8 @@
* test IPrintManager.getPrintJobInfo
*/
public void testGetPrintJobInfo() throws Exception {
+ startPrinting();
+
assertEquals(mGoodPrintJob.getId(), mIPrintManager.getPrintJobInfo(mGoodPrintJob.getId(),
mAppId, mUserId).getId());
assertEquals(null, mIPrintManager.getPrintJobInfo(mBadPrintJobId, mAppId, mUserId));
@@ -274,6 +275,8 @@
* test IPrintManager.getPrintJobInfos
*/
public void testGetPrintJobInfos() throws Exception {
+ startPrinting();
+
List<PrintJobInfo> infos = mIPrintManager.getPrintJobInfos(mAppId, mUserId);
boolean foundPrintJob = false;
@@ -304,7 +307,7 @@
final IPrintDocumentAdapter adapter = new PrintManager
.PrintDocumentAdapterDelegate(getActivity(), createMockAdapter());
- // Valid parameters are tested in setUp()
+ startPrinting();
assertException(new Invokable() {
@Override
@@ -352,6 +355,8 @@
* test IPrintManager.cancelPrintJob
*/
public void testCancelPrintJob() throws Exception {
+ startPrinting();
+
// Invalid print jobs IDs do not produce an exception
mIPrintManager.cancelPrintJob(mBadPrintJobId, mAppId, mUserId);
mIPrintManager.cancelPrintJob(null, mAppId, mUserId);
@@ -373,6 +378,8 @@
* test IPrintManager.restartPrintJob
*/
public void testRestartPrintJob() throws Exception {
+ startPrinting();
+
mIPrintManager.restartPrintJob(mGoodPrintJob.getId(), mAppId, mUserId);
// Invalid print jobs IDs do not produce an exception
@@ -438,22 +445,103 @@
}
/**
- * test IPrintManager.getInstalledPrintServices
+ * test IPrintManager.addPrintServicesChangeListener
*/
- public void testGetInstalledPrintServices() throws Exception {
- List<PrintServiceInfo> printServices = mIPrintManager.getInstalledPrintServices(mUserId);
- assertTrue(printServices.size() >= 2);
+ public void testAddPrintServicesChangeListener() throws Exception {
+ final IPrintServicesChangeListener listener = createMockIPrintServicesChangeListener();
+
+ mIPrintManager.addPrintServicesChangeListener(listener, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.addPrintServicesChangeListener(null, mUserId);
+ }
+ }, NullPointerException.class);
// Cannot test bad user Id as these tests are allowed to call across users
}
/**
- * test IPrintManager.getEnabledPrintServices
+ * test IPrintManager.removePrintServicesChangeListener
*/
- public void testGetEnabledPrintServices() throws Exception {
- List<PrintServiceInfo> printServices = mIPrintManager.getEnabledPrintServices(mUserId);
+ public void testRemovePrintServicesChangeListener() throws Exception {
+ final IPrintServicesChangeListener listener = createMockIPrintServicesChangeListener();
+
+ mIPrintManager.addPrintServicesChangeListener(listener, mUserId);
+ mIPrintManager.removePrintServicesChangeListener(listener, mUserId);
+
+ // Removing unknown listeners is a no-op
+ mIPrintManager.removePrintServicesChangeListener(listener, mUserId);
+
+ mIPrintManager.addPrintServicesChangeListener(listener, mUserId);
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.removePrintServicesChangeListener(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.getPrintServices
+ */
+ public void testGetPrintServices() throws Exception {
+ List<PrintServiceInfo> printServices = mIPrintManager.getPrintServices(
+ PrintManager.ALL_SERVICES, mUserId);
assertTrue(printServices.size() >= 2);
+ printServices = mIPrintManager.getPrintServices(0, mUserId);
+ assertEquals(printServices, null);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.getPrintServices(~PrintManager.ALL_SERVICES, mUserId);
+ }
+ }, IllegalArgumentException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.setPrintServiceEnabled
+ */
+ public void testSetPrintServiceEnabled() throws Exception {
+ final ComponentName printService = mIPrintManager.getPrintServices(
+ PrintManager.ALL_SERVICES, mUserId).get(0).getComponentName();
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.setPrintServiceEnabled(printService, false, mUserId);
+ }
+ }, SecurityException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.setPrintServiceEnabled(printService, true, mUserId);
+ }
+ }, SecurityException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.setPrintServiceEnabled(new ComponentName("bad", "name"), true,
+ mUserId);
+ }
+ }, SecurityException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.setPrintServiceEnabled(null, true, mUserId);
+ }
+ }, SecurityException.class);
+
// Cannot test bad user Id as these tests are allowed to call across users
}
@@ -486,6 +574,8 @@
* test IPrintManager.startPrinterDiscovery
*/
public void testStartPrinterDiscovery() throws Exception {
+ startPrinting();
+
final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
final List<PrinterId> goodPrinters = new ArrayList<>();
goodPrinters.add(mGoodPrinterId);
@@ -549,6 +639,8 @@
* test IPrintManager.validatePrinters
*/
public void testValidatePrinters() throws Exception {
+ startPrinting();
+
final List<PrinterId> goodPrinters = new ArrayList<>();
goodPrinters.add(mGoodPrinterId);
@@ -587,6 +679,8 @@
* test IPrintManager.startPrinterStateTracking
*/
public void testStartPrinterStateTracking() throws Exception {
+ startPrinting();
+
mIPrintManager.startPrinterStateTracking(mGoodPrinterId, mUserId);
// Bad printers do no cause exceptions
@@ -606,6 +700,8 @@
* test IPrintManager.getCustomPrinterIcon
*/
public void testGetCustomPrinterIcon() throws Exception {
+ startPrinting();
+
mIPrintManager.getCustomPrinterIcon(mGoodPrinterId, mUserId);
// Bad printers do no cause exceptions
@@ -625,6 +721,8 @@
* test IPrintManager.stopPrinterStateTracking
*/
public void testStopPrinterStateTracking() throws Exception {
+ startPrinting();
+
mIPrintManager.startPrinterStateTracking(mGoodPrinterId, mUserId);
mIPrintManager.stopPrinterStateTracking(mGoodPrinterId, mUserId);
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/transition/SlideTransitionTest.java b/core/tests/coretests/src/android/transition/SlideTransitionTest.java
new file mode 100644
index 0000000..8b9ec74
--- /dev/null
+++ b/core/tests/coretests/src/android/transition/SlideTransitionTest.java
@@ -0,0 +1,174 @@
+/*
+ * 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.transition;
+
+import android.animation.AnimatorSetActivity;
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+
+import com.android.frameworks.coretests.R;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+
+public class SlideTransitionTest extends ActivityInstrumentationTestCase2<AnimatorSetActivity> {
+
+ Activity mActivity;
+
+ public SlideTransitionTest() {
+ super(AnimatorSetActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ mActivity = getActivity();
+ }
+
+ @SmallTest
+ public void testShortSlide() throws Throwable {
+ final float slideFraction = 0.5f;
+ final View square1 = mActivity.findViewById(R.id.square1);
+ final View sceneRoot = mActivity.findViewById(R.id.container);
+ final SlideTranslationValueRatchet ratchet = new SlideTranslationValueRatchet(square1);
+ square1.getViewTreeObserver().addOnPreDrawListener(ratchet);
+
+ final Slide slideOut = new Slide(Gravity.BOTTOM);
+ final float finalOffsetOut = sceneRoot.getHeight() * slideFraction;
+ slideOut.setSlideFraction(slideFraction);
+ TransitionLatch latch = setVisibilityInTransition(slideOut, R.id.square1, View.INVISIBLE);
+ assertTrue(latch.startLatch.await(200, TimeUnit.MILLISECONDS));
+ assertEquals(0f, square1.getTranslationY(), 0.1f);
+ assertEquals(View.VISIBLE, square1.getVisibility());
+ Thread.sleep(100);
+ assertFalse(square1.getTranslationY() < 0.1
+ || square1.getTranslationY() > finalOffsetOut - 0.1);
+ assertTrue(latch.endLatch.await(400, TimeUnit.MILLISECONDS));
+ // Give this 20% slop in case some frames get dropped.
+ assertTrue(finalOffsetOut * 0.8 < ratchet.maxY);
+ assertTrue(finalOffsetOut + 0.1 > ratchet.maxY);
+ assertEquals(View.INVISIBLE, square1.getVisibility());
+
+ ratchet.reset();
+ final Slide slideIn = new Slide(Gravity.BOTTOM);
+ final float initialOffsetIn = sceneRoot.getHeight() * slideFraction;
+ slideIn.setSlideFraction(slideFraction);
+ latch = setVisibilityInTransition(slideIn, R.id.square1, View.VISIBLE);
+ assertTrue(latch.startLatch.await(200, TimeUnit.MILLISECONDS));
+ assertEquals(initialOffsetIn, square1.getTranslationY(), 0.1f);
+ assertEquals(View.VISIBLE, square1.getVisibility());
+ Thread.sleep(100);
+ assertFalse(square1.getTranslationY() < 0.1
+ || square1.getTranslationY() > initialOffsetIn - 0.1);
+ assertTrue(latch.endLatch.await(400, TimeUnit.MILLISECONDS));
+ assertEquals(0f, ratchet.minY, 0.1);
+ assertEquals(0f, square1.getTranslationY(), 0.1);
+ assertEquals(View.VISIBLE, square1.getVisibility());
+
+ square1.getViewTreeObserver().removeOnPreDrawListener(ratchet);
+ }
+
+ public TransitionLatch setVisibilityInTransition(final Transition transition, int viewId,
+ final int visibility) throws Throwable {
+ final ViewGroup sceneRoot = (ViewGroup) mActivity.findViewById(R.id.container);
+ final View view = sceneRoot.findViewById(viewId);
+ TransitionLatch latch = new TransitionLatch();
+ transition.addListener(latch);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ TransitionManager.beginDelayedTransition(sceneRoot, transition);
+ view.setVisibility(visibility);
+ }
+ });
+ return latch;
+ }
+
+ public static class TransitionLatch implements Transition.TransitionListener {
+ public CountDownLatch startLatch = new CountDownLatch(1);
+ public CountDownLatch endLatch = new CountDownLatch(1);
+ public CountDownLatch cancelLatch = new CountDownLatch(1);
+ public CountDownLatch pauseLatch = new CountDownLatch(1);
+ public CountDownLatch resumeLatch = new CountDownLatch(1);
+
+ @Override
+ public void onTransitionStart(Transition transition) {
+ startLatch.countDown();
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ endLatch.countDown();
+ transition.removeListener(this);
+ }
+
+ @Override
+ public void onTransitionCancel(Transition transition) {
+ cancelLatch.countDown();
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+ pauseLatch.countDown();
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ resumeLatch.countDown();
+ }
+ }
+
+ private static class SlideTranslationValueRatchet
+ implements ViewTreeObserver.OnPreDrawListener {
+
+ private final View mView;
+ private boolean mInitialized;
+ public float minX = Float.NaN;
+ public float minY = Float.NaN;
+ public float maxX = Float.NaN;
+ public float maxY = Float.NaN;
+
+ public SlideTranslationValueRatchet(View view) {
+ mView = view;
+ }
+
+ public void reset() {
+ minX = minY = maxX = maxY = Float.NaN;
+ mInitialized = false;
+ }
+
+ @Override
+ public boolean onPreDraw() {
+ if (!mInitialized) {
+ minX = maxX = mView.getTranslationX();
+ minY = maxY = mView.getTranslationY();
+ mInitialized = true;
+ } else {
+ minX = Math.min(minX, mView.getTranslationX());
+ minY = Math.min(minY, mView.getTranslationY());
+ maxX = Math.max(maxX, mView.getTranslationX());
+ maxY = Math.max(maxY, mView.getTranslationY());
+ }
+ return true;
+ }
+ }
+}
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/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
index b9c2da7..deba40f 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
@@ -50,6 +50,22 @@
}
@SmallTest
+ public void testFilterDoesNotMatchAnything() throws Exception {
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("en-US"));
+ availableLocales.add(Locale.forLanguageTag("fr-CA"));
+ availableLocales.add(Locale.forLanguageTag("in"));
+ availableLocales.add(Locale.forLanguageTag("ja"));
+ availableLocales.add(Locale.forLanguageTag("fil"));
+
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("zh-Hans-TW");
+
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(0, dest.size());
+ }
+
+ @SmallTest
public void testFilterByLanguageEmptySource() throws Exception {
final ArrayList<Locale> availableLocales = new ArrayList<>();
@@ -124,21 +140,36 @@
@SmallTest
public void testFilterByLanguage() throws Exception {
- final ArrayList<Locale> availableLocales = new ArrayList<>();
- availableLocales.add(Locale.forLanguageTag("en-US"));
- availableLocales.add(Locale.forLanguageTag("fr-CA"));
- availableLocales.add(Locale.forLanguageTag("in"));
- availableLocales.add(Locale.forLanguageTag("ja"));
- availableLocales.add(Locale.forLanguageTag("fil"));
+ {
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("en-US"));
+ availableLocales.add(Locale.forLanguageTag("fr-CA"));
+ availableLocales.add(Locale.forLanguageTag("in"));
+ availableLocales.add(Locale.forLanguageTag("ja"));
+ availableLocales.add(Locale.forLanguageTag("fil"));
- final LocaleList preferredLocales = LocaleList.forLanguageTags("fr,en-US,ja-JP");
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("fr,en-US,ja-JP");
- final ArrayList<Locale> dest = new ArrayList<>();
- LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
- assertEquals(3, dest.size());
- assertEquals(availableLocales.get(1), dest.get(0)); // "fr-CA"
- assertEquals(availableLocales.get(0), dest.get(1)); // "en-US"
- assertEquals(availableLocales.get(3), dest.get(2)); // "ja"
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(3, dest.size());
+ assertEquals(availableLocales.get(1), dest.get(0)); // "fr-CA"
+ assertEquals(availableLocales.get(0), dest.get(1)); // "en-US"
+ assertEquals(availableLocales.get(3), dest.get(2)); // "ja"
+ }
+ {
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("en-US"));
+ availableLocales.add(Locale.forLanguageTag("en-GB"));
+ availableLocales.add(Locale.forLanguageTag("en-IN"));
+
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("en-US");
+
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(0), dest.get(0)); // "en-US"
+ }
}
@SmallTest
@@ -191,4 +222,165 @@
assertEquals(availableLocales.get(1), dest.get(0)); // "en-CA"
}
}
+
+ @SmallTest
+ public void testFilterByLanguageFallbackRules() throws Exception {
+ {
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-Latn-RS");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl-BA"));
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl-CS"));
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl-ME"));
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl-RS"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn-BA"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn-CS"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn-ME"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn-RS"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(7), dest.get(0)); // "sr-Latn-RS"
+ }
+ {
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-Latn-RS-x-android");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl-BA"));
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl-CS"));
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl-ME"));
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl-RS"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn-BA"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn-CS"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn-ME"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn-RS"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(7), dest.get(0)); // "sr-Latn-RS"
+ }
+ {
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-Latn-RS");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl-BA-x-android"));
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl-CS-x-android"));
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl-ME-x-android"));
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl-RS-x-android"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn-BA-x-android"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn-CS-x-android"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn-ME-x-android"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn-RS-x-android"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(7), dest.get(0)); // "sr-Latn-RS-x-android"
+ }
+
+ {
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-Latn-RS");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("sr"));
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(2), dest.get(0)); // "sr-Latn"
+ }
+
+ {
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-RS");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("sr"));
+ availableLocales.add(Locale.forLanguageTag("sr-RS"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(0), dest.get(0)); // "sr"
+ }
+
+ {
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-Latn");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("sr"));
+ availableLocales.add(Locale.forLanguageTag("sr-RS"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(2), dest.get(0)); // "sr-Latn"
+ }
+
+ {
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("sr");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("sr"));
+ availableLocales.add(Locale.forLanguageTag("sr-RS"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(0), dest.get(0)); // "sr"
+ }
+ {
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("sr");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("sr-Latn"));
+ availableLocales.add(Locale.forLanguageTag("sr-RS"));
+ availableLocales.add(Locale.forLanguageTag("sr"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(1), dest.get(0)); // "sr-RS"
+ }
+
+ {
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("sr");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl-RS"));
+ availableLocales.add(Locale.forLanguageTag("sr-Latn-RS"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(0), dest.get(0)); // "sr-Cyrl-RS"
+ }
+ {
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("sr-Latn");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("sr-Latn-RS"));
+ availableLocales.add(Locale.forLanguageTag("sr-Cyrl-RS"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(0), dest.get(0)); // "sr-Latn-RS"
+ }
+ }
+
+ public void testFilterKnownLimitation() throws Exception {
+ // Following test cases are not for intentional behavior but checks for preventing the
+ // behavior from becoming worse.
+ {
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("ja-Hrkt");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("ja-Jpan"));
+ availableLocales.add(Locale.forLanguageTag("ja-Hrkt"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ // Should be ja-Jpan since it supports ja-Hrkt and listed before ja-Hrkt.
+ assertEquals(availableLocales.get(1), dest.get(0));
+ }
+ {
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("zh-Hani");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("zh-Hans"));
+ availableLocales.add(Locale.forLanguageTag("zh-Hant"));
+ availableLocales.add(Locale.forLanguageTag("zh-Hanb"));
+ availableLocales.add(Locale.forLanguageTag("zh-Hani"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ // Should be zh-Hans since it supports zh-Hani. Also zh-Hant, zh-Hanb supports zh-Hani.
+ assertEquals(availableLocales.get(3), dest.get(0));
+ }
+ }
}
diff --git a/data/keyboards/qwerty2.kcm b/data/keyboards/qwerty2.kcm
index d96914f..b981d83 100644
--- a/data/keyboards/qwerty2.kcm
+++ b/data/keyboards/qwerty2.kcm
@@ -23,8 +23,8 @@
number: '2'
base: 'a'
shift, capslock: 'A'
- alt: 'a'
- shift+alt, capslock+alt: 'A'
+ alt: '\u00e1'
+ shift+alt, capslock+alt: '\u00c1'
}
key B {
@@ -41,8 +41,8 @@
number: '2'
base: 'c'
shift, capslock: 'C'
- alt: '\u00e7'
- shift+alt, capslock+alt: '\u00e7'
+ alt: '\u00a9'
+ shift+alt, capslock+alt: '\u00a2'
}
key D {
@@ -50,8 +50,8 @@
number: '3'
base: 'd'
shift, capslock: 'D'
- alt: '\''
- shift+alt, capslock+alt: '\''
+ alt: '\u00f0'
+ shift+alt, capslock+alt: '\u00d0'
}
key E {
@@ -59,8 +59,8 @@
number: '3'
base: 'e'
shift, capslock: 'E'
- alt: '"'
- shift+alt, capslock+alt: '\u0301'
+ alt: '\u00e9'
+ shift+alt, capslock+alt: '\u00c9'
}
key F {
@@ -95,8 +95,8 @@
number: '4'
base: 'i'
shift, capslock: 'I'
- alt: '-'
- shift+alt, capslock+alt: '\u0302'
+ alt: '\u00ed'
+ shift+alt, capslock+alt: '\u00cd'
}
key J {
@@ -122,8 +122,8 @@
number: '5'
base: 'l'
shift, capslock: 'L'
- alt: ':'
- shift+alt, capslock+alt: '`'
+ alt: '\u00f8'
+ shift+alt, capslock+alt: '\u00d8'
}
key M {
@@ -131,7 +131,7 @@
number: '6'
base: 'm'
shift, capslock: 'M'
- alt: '%'
+ alt: '\u00b5'
shift+alt, capslock+alt: none
}
@@ -140,8 +140,8 @@
number: '6'
base: 'n'
shift, capslock: 'N'
- alt: none
- shift+alt, capslock+alt: '\u0303'
+ alt: '\u00f1'
+ shift+alt, capslock+alt: '\u00d1'
}
key O {
@@ -149,8 +149,8 @@
number: '6'
base: 'o'
shift, capslock: 'O'
- alt: '+'
- shift+alt, capslock+alt: '+'
+ alt: '\u00f3'
+ shift+alt, capslock+alt: '\u00d3'
}
key P {
@@ -158,8 +158,8 @@
number: '7'
base: 'p'
shift, capslock: 'P'
- alt: '='
- shift+alt, capslock+alt: '\u00a5'
+ alt: '\u00f6'
+ shift+alt, capslock+alt: '\u00d6'
}
key Q {
@@ -167,8 +167,8 @@
number: '7'
base: 'q'
shift, capslock: 'Q'
- alt: '|'
- shift+alt, capslock+alt: '\u0300'
+ alt: '\u00e4'
+ shift+alt, capslock+alt: '\u00c4'
}
key R {
@@ -176,8 +176,8 @@
number: '7'
base: 'r'
shift, capslock: 'R'
- alt: '`'
- shift+alt, capslock+alt: '\u20ac'
+ alt: '\u00ae'
+ shift+alt, capslock+alt: 'R'
}
key S {
@@ -185,8 +185,8 @@
number: '7'
base: 's'
shift, capslock: 'S'
- alt: '\\'
- shift+alt, capslock+alt: '\u00df'
+ alt: '\u00df'
+ shift+alt, capslock+alt: '\u00a7'
}
key T {
@@ -194,8 +194,8 @@
number: '8'
base: 't'
shift, capslock: 'T'
- alt: '{'
- shift+alt, capslock+alt: '\u00a3'
+ alt: '\u00fe'
+ shift+alt, capslock+alt: '\u00de'
}
key U {
@@ -203,8 +203,8 @@
number: '8'
base: 'u'
shift, capslock: 'U'
- alt: '_'
- shift+alt, capslock+alt: '\u0308'
+ alt: '\u00fa'
+ shift+alt, capslock+alt: '\u00da'
}
key V {
@@ -221,8 +221,8 @@
number: '9'
base: 'w'
shift, capslock: 'W'
- alt: '~'
- shift+alt, capslock+alt: '~'
+ alt: '\u00e5'
+ shift+alt, capslock+alt: '\u00c5'
}
key X {
@@ -239,8 +239,8 @@
number: '9'
base: 'y'
shift, capslock: 'Y'
- alt: '}'
- shift+alt, capslock+alt: '\u00a1'
+ alt: '\u00fc'
+ shift+alt, capslock+alt: '\u00dc'
}
key Z {
@@ -248,8 +248,8 @@
number: '9'
base: 'z'
shift, capslock: 'Z'
- alt: 'z'
- shift+alt, capslock+alt: 'Z'
+ alt: '\u00e6'
+ shift+alt, capslock+alt: '\u00c6'
}
key COMMA {
@@ -257,8 +257,8 @@
number: ','
base: ','
shift: '<'
- alt: ','
- shift+alt: ','
+ alt: '\u00e7'
+ shift+alt: '\u00c7'
}
key PERIOD {
@@ -284,7 +284,7 @@
number: '/'
base: '/'
shift: '?'
- alt: '?'
+ alt: '\u00bf'
shift+alt: '?'
}
@@ -320,7 +320,7 @@
number: '0'
base: '0'
shift: ')'
- alt: ')'
+ alt: '\u02bc'
shift+alt: ')'
}
@@ -329,8 +329,8 @@
number: '1'
base: '1'
shift: '!'
- alt: '!'
- shift+alt: '!'
+ alt: '\u00a1'
+ shift+alt: '\u00b9'
}
key 2 {
@@ -338,7 +338,7 @@
number: '2'
base: '2'
shift: '@'
- alt: '@'
+ alt: '\u00b2'
shift+alt: '@'
}
@@ -347,7 +347,7 @@
number: '3'
base: '3'
shift: '#'
- alt: '#'
+ alt: '\u00b3'
shift+alt: '#'
}
@@ -356,8 +356,8 @@
number: '4'
base: '4'
shift: '$'
- alt: '$'
- shift+alt: '$'
+ alt: '\u00a4'
+ shift+alt: '\u00a3'
}
key 5 {
@@ -365,7 +365,7 @@
number: '5'
base: '5'
shift: '%'
- alt: '%'
+ alt: '\u20ac'
shift+alt: '%'
}
@@ -374,8 +374,8 @@
number: '6'
base: '6'
shift: '^'
- alt: '^'
- shift+alt: '^'
+ alt: '\u00bc'
+ shift+alt: '\u0302'
}
key 7 {
@@ -383,7 +383,7 @@
number: '7'
base: '7'
shift: '&'
- alt: '&'
+ alt: '\u00bd'
shift+alt: '&'
}
@@ -392,7 +392,7 @@
number: '8'
base: '8'
shift: '*'
- alt: '*'
+ alt: '\u00be'
shift+alt: '*'
}
@@ -401,7 +401,7 @@
number: '9'
base: '9'
shift: '('
- alt: '('
+ alt: '\u02bb'
shift+alt: '('
}
@@ -410,8 +410,8 @@
number: '`'
base: '`'
shift: '~'
- alt: '`'
- shift+alt: '~'
+ alt: '\u0300'
+ shift+alt: '\u0303'
}
key MINUS {
@@ -419,7 +419,7 @@
number: '-'
base: '-'
shift: '_'
- alt: '-'
+ alt: '\u00a5'
shift+alt: '_'
}
@@ -428,8 +428,8 @@
number: '='
base: '='
shift: '+'
- alt: '='
- shift+alt: '+'
+ alt: '\u00d7'
+ shift+alt: '\u00f7'
}
key LEFT_BRACKET {
@@ -437,7 +437,7 @@
number: '['
base: '['
shift: '{'
- alt: '['
+ alt: '\u00ab'
shift+alt: '{'
}
@@ -446,7 +446,7 @@
number: ']'
base: ']'
shift: '}'
- alt: ']'
+ alt: '\u00bb'
shift+alt: '}'
}
@@ -455,8 +455,8 @@
number: '\\'
base: '\\'
shift: '|'
- alt: '\\'
- shift+alt: '|'
+ alt: '\u00ac'
+ shift+alt: '\u00a6'
}
key SEMICOLON {
@@ -464,8 +464,8 @@
number: ';'
base: ';'
shift: ':'
- alt: ';'
- shift+alt: ':'
+ alt: '\u00b6'
+ shift+alt: '\u00b0'
}
key APOSTROPHE {
@@ -473,8 +473,8 @@
number: '\''
base: '\''
shift: '"'
- alt: '\''
- shift+alt: '"'
+ alt: '\u0301'
+ shift+alt: '\u0308'
}
key STAR {
diff --git a/docs/html/guide/topics/sensors/sensors_overview.jd b/docs/html/guide/topics/sensors/sensors_overview.jd
index 0b3cb2b..53faca0 100644
--- a/docs/html/guide/topics/sensors/sensors_overview.jd
+++ b/docs/html/guide/topics/sensors/sensors_overview.jd
@@ -465,6 +465,7 @@
...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
+mSensor = null;
if (mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){
List<Sensor> gravSensors = mSensorManager.getSensorList(Sensor.TYPE_GRAVITY);
@@ -476,7 +477,7 @@
}
}
}
-else{
+if (mSensor == null){
// Use the accelerometer.
if (mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
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 d8801b8..6813c89 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 3277c36..bf6ff11 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -1869,8 +1869,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;
@@ -2015,11 +2015,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;
@@ -2534,7 +2534,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;
@@ -2683,8 +2684,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("-");
@@ -2714,7 +2715,7 @@
size_t len = unpackLanguage(buf);
out.append(buf, len);
- if (localeScriptWasProvided) {
+ if (scriptWasProvided) {
out.append("+");
out.append(localeScript, sizeof(localeScript));
}
@@ -2745,7 +2746,7 @@
charsWritten += unpackLanguage(str);
}
- if (localeScriptWasProvided) {
+ if (localeScript[0] && !localeScriptWasComputed) {
if (charsWritten) {
str[charsWritten++] = '-';
}
@@ -2786,7 +2787,6 @@
for (size_t i = 1; i < 4; ++i) {
config->localeScript[i] = tolower(start[i]);
}
- config->localeScriptWasProvided = true;
break;
}
case 5:
@@ -2806,7 +2806,6 @@
void ResTable_config::setBcp47Locale(const char* in) {
locale = 0;
- localeScriptWasProvided = false;
memset(localeScript, 0, sizeof(localeScript));
memset(localeVariant, 0, sizeof(localeVariant));
@@ -2823,9 +2822,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 1aab3c7..06b712e 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -30,6 +30,7 @@
#include <algorithm>
#include <math.h>
#include <SkPaintDefaults.h>
+#include <SkPathOps.h>
namespace android {
namespace uirenderer {
@@ -60,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();
@@ -527,6 +531,12 @@
SkPath path;
SkRect rect = getBoundsOfFill(op);
path.addOval(rect);
+
+ if (state.computedState.localProjectionPathMask != nullptr) {
+ // Mask the ripple path by the local space projection mask in local space.
+ // Note that this can create CCW paths.
+ Op(path, *state.computedState.localProjectionPathMask, kIntersect_SkPathOp, &path);
+ }
renderConvexPath(renderer, state, path, *(op.paint));
}
}
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index c147384..98493d7 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -135,17 +135,7 @@
mRenderState.stencil().disable();
}
- mCaches.clearGarbage();
- mCaches.pathCache.trim();
- mCaches.tessellationCache.trim();
-
-#if DEBUG_MEMORY_USAGE
- mCaches.dumpMemoryUsage();
-#else
- if (Properties::debugLevel & kDebugMemory) {
- mCaches.dumpMemoryUsage();
- }
-#endif
+ // Note: we leave FBO 0 renderable here, for post-frame-content decoration
}
void BakedOpRenderer::setViewport(uint32_t width, uint32_t height) {
@@ -179,6 +169,38 @@
return texture;
}
+void BakedOpRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
+ std::vector<Vertex> vertices;
+ vertices.reserve(count);
+ Vertex* vertex = vertices.data();
+
+ for (int index = 0; index < count; index += 4) {
+ float l = rects[index + 0];
+ float t = rects[index + 1];
+ float r = rects[index + 2];
+ float b = rects[index + 3];
+
+ Vertex::set(vertex++, l, t);
+ Vertex::set(vertex++, r, t);
+ Vertex::set(vertex++, l, b);
+ Vertex::set(vertex++, r, b);
+ }
+
+ LOG_ALWAYS_FATAL_IF(mRenderTarget.frameBufferId != 0, "decoration only supported for FBO 0");
+ // TODO: Currently assume full FBO damage, due to FrameInfoVisualizer::unionDirty.
+ // Should should scissor safely.
+ mRenderState.scissor().setEnabled(false);
+ Glop glop;
+ GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(nullptr)
+ .setMeshIndexedQuads(vertices.data(), count / 4)
+ .setFillPaint(*paint, 1.0f)
+ .setTransform(Matrix4::identity(), TransformFlags::None)
+ .setModelViewIdentityEmptyBounds()
+ .build();
+ mRenderState.render(glop, mRenderTarget.orthoMatrix);
+}
+
// clears and re-fills stencil with provided rendertarget space quads,
// and then put stencil into test mode
void BakedOpRenderer::setupStencilQuads(std::vector<Vertex>& quadVertices,
diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h
index 55ea935..4b65255 100644
--- a/libs/hwui/BakedOpRenderer.h
+++ b/libs/hwui/BakedOpRenderer.h
@@ -85,6 +85,16 @@
bool offscreenRenderTarget() { return mRenderTarget.offscreenBuffer != nullptr; }
void dirtyRenderTarget(const Rect& dirtyRect);
bool didDraw() const { return mHasDrawn; }
+
+ uint32_t getViewportWidth() const { return mRenderTarget.viewportWidth; }
+ uint32_t getViewportHeight() const { return mRenderTarget.viewportHeight; }
+
+ // simple draw methods, to be used for end frame decoration
+ void drawRect(float left, float top, float right, float bottom, const SkPaint* paint) {
+ float ltrb[4] = { left, top, right, bottom };
+ drawRects(ltrb, 4, paint);
+ }
+ void drawRects(const float* rects, int count, const SkPaint* paint);
private:
void setViewport(uint32_t width, uint32_t height);
void clearColorBuffer(const Rect& clearRect);
diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp
index 682bd04..26653f7 100644
--- a/libs/hwui/BakedOpState.cpp
+++ b/libs/hwui/BakedOpState.cpp
@@ -63,9 +63,22 @@
clipState = nullptr;
clippedBounds.setEmpty();
} else {
- // Not rejected! compute true clippedBounds and clipSideFlags
+ // Not rejected! compute true clippedBounds, clipSideFlags, and path mask
clipSideFlags = computeClipSideFlags(clipRect, clippedBounds);
clippedBounds.doIntersect(clipRect);
+
+ if (CC_UNLIKELY(snapshot.projectionPathMask)) {
+ // map projection path mask from render target space into op space,
+ // so intersection with op geometry is possible
+ Matrix4 inverseTransform;
+ inverseTransform.loadInverse(transform);
+ SkMatrix skInverseTransform;
+ inverseTransform.copyTo(skInverseTransform);
+
+ auto localMask = allocator.create<SkPath>();
+ snapshot.projectionPathMask->transform(skInverseTransform, localMask);
+ localProjectionPathMask = localMask;
+ }
}
}
@@ -73,13 +86,15 @@
: transform(*snapshot.transform)
, clipState(snapshot.mutateClipArea().serializeClip(allocator))
, clippedBounds(clipState->rect)
- , clipSideFlags(OpClipSideFlags::Full) {}
+ , clipSideFlags(OpClipSideFlags::Full)
+ , localProjectionPathMask(nullptr) {}
ResolvedRenderState::ResolvedRenderState(const ClipRect* clipRect, const Rect& dstRect)
: transform(Matrix4::identity())
, clipState(clipRect)
, clippedBounds(dstRect)
- , clipSideFlags(computeClipSideFlags(clipRect->rect, dstRect)) {
+ , clipSideFlags(computeClipSideFlags(clipRect->rect, dstRect))
+ , localProjectionPathMask(nullptr) {
clippedBounds.doIntersect(clipRect->rect);
}
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index 4365ef8..ffe2901 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -88,6 +88,7 @@
const ClipBase* clipState = nullptr;
Rect clippedBounds;
int clipSideFlags = 0;
+ const SkPath* localProjectionPathMask = nullptr;
};
/**
@@ -154,7 +155,6 @@
// simple state (straight pointer/value storage):
const float alpha;
const RoundRectClipState* roundRectClipState;
- const ProjectionPathMask* projectionPathMask;
const RecordedOp* op;
private:
@@ -165,21 +165,18 @@
: computedState(allocator, snapshot, recordedOp, expandForStroke)
, alpha(snapshot.alpha)
, roundRectClipState(snapshot.roundRectClipState)
- , projectionPathMask(snapshot.projectionPathMask)
, op(&recordedOp) {}
BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const ShadowOp* shadowOpPtr)
: computedState(allocator, snapshot)
, alpha(snapshot.alpha)
, roundRectClipState(snapshot.roundRectClipState)
- , projectionPathMask(snapshot.projectionPathMask)
, op(shadowOpPtr) {}
BakedOpState(const ClipRect* clipRect, const Rect& dstRect, const RecordedOp& recordedOp)
: computedState(clipRect, dstRect)
, alpha(1.0f)
, roundRectClipState(nullptr)
- , projectionPathMask(nullptr)
, op(&recordedOp) {}
};
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 04de98a..fd5856a 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -203,8 +203,9 @@
mCanvasState.setClippingOutline(mAllocator, &(properties.getOutline()));
}
- bool quickRejected = properties.getClipToBounds()
- && mCanvasState.quickRejectConservative(0, 0, width, height);
+ bool quickRejected = mCanvasState.currentSnapshot()->getRenderTargetClip().isEmpty()
+ || (properties.getClipToBounds()
+ && mCanvasState.quickRejectConservative(0, 0, width, height));
if (!quickRejected) {
// not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer)
if (node.getLayer()) {
@@ -389,34 +390,38 @@
}
void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) {
- const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath();
int count = mCanvasState.save(SaveFlags::MatrixClip);
+ const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath();
- // can't be null, since DL=null node rejection happens before deferNodePropsAndOps
- const DisplayList& displayList = *(renderNode.getDisplayList());
-
- const RecordedOp* op = (displayList.getOps()[displayList.projectionReceiveIndex]);
- const RenderNodeOp* backgroundOp = static_cast<const RenderNodeOp*>(op);
- const RenderProperties& backgroundProps = backgroundOp->renderNode->properties();
-
- // Transform renderer to match background we're projecting onto
- // (by offsetting canvas by translationX/Y of background rendernode, since only those are set)
- mCanvasState.translate(backgroundProps.getTranslationX(), backgroundProps.getTranslationY());
-
- // If the projection receiver has an outline, we mask projected content to it
- // (which we know, apriori, are all tessellated paths)
- mCanvasState.setProjectionPathMask(mAllocator, projectionReceiverOutline);
-
- // draw projected nodes
- for (size_t i = 0; i < renderNode.mProjectedNodes.size(); i++) {
- RenderNodeOp* childOp = renderNode.mProjectedNodes[i];
-
- int restoreTo = mCanvasState.save(SaveFlags::Matrix);
- mCanvasState.concatMatrix(childOp->transformFromCompositingAncestor);
- deferRenderNodeOpImpl(*childOp);
- mCanvasState.restoreToCount(restoreTo);
+ SkPath transformedMaskPath; // on stack, since BakedOpState makes a deep copy
+ if (projectionReceiverOutline) {
+ // transform the mask for this projector into render target space
+ // TODO: consider combining both transforms by stashing transform instead of applying
+ SkMatrix skCurrentTransform;
+ mCanvasState.currentTransform()->copyTo(skCurrentTransform);
+ projectionReceiverOutline->transform(
+ skCurrentTransform,
+ &transformedMaskPath);
+ mCanvasState.setProjectionPathMask(mAllocator, &transformedMaskPath);
}
+ for (size_t i = 0; i < renderNode.mProjectedNodes.size(); i++) {
+ RenderNodeOp* childOp = renderNode.mProjectedNodes[i];
+ RenderNode& childNode = *childOp->renderNode;
+
+ // Draw child if it has content, but ignore state in childOp - matrix already applied to
+ // transformFromCompositingAncestor, and record-time clip is ignored when projecting
+ if (!childNode.nothingToDraw()) {
+ int restoreTo = mCanvasState.save(SaveFlags::MatrixClip);
+
+ // Apply transform between ancestor and projected descendant
+ mCanvasState.concatMatrix(childOp->transformFromCompositingAncestor);
+
+ deferNodePropsAndOps(childNode);
+
+ mCanvasState.restoreToCount(restoreTo);
+ }
+ }
mCanvasState.restoreToCount(count);
}
@@ -513,10 +518,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()
@@ -531,7 +532,6 @@
} else {
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
}
-*/
}
void FrameBuilder::deferBitmapMeshOp(const BitmapMeshOp& op) {
diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp
index b7dd3b7..adadd32 100644
--- a/libs/hwui/FrameInfoVisualizer.cpp
+++ b/libs/hwui/FrameInfoVisualizer.cpp
@@ -15,7 +15,11 @@
*/
#include "FrameInfoVisualizer.h"
+#if HWUI_NEW_OPS
+#include "BakedOpRenderer.h"
+#else
#include "OpenGLRenderer.h"
+#endif
#include "utils/Color.h"
#include <cutils/compiler.h>
@@ -88,7 +92,7 @@
}
}
-void FrameInfoVisualizer::draw(OpenGLRenderer* canvas) {
+void FrameInfoVisualizer::draw(ContentRenderer* renderer) {
RETURN_IF_DISABLED();
if (mShowDirtyRegions) {
@@ -96,7 +100,7 @@
if (mFlashToggle) {
SkPaint paint;
paint.setColor(0x7fff0000);
- canvas->drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop,
+ renderer->drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop,
mDirtyRegion.fRight, mDirtyRegion.fBottom, &paint);
}
}
@@ -111,9 +115,9 @@
info.markSwapBuffers();
info.markFrameCompleted();
- initializeRects(canvas->getViewportHeight(), canvas->getViewportWidth());
- drawGraph(canvas);
- drawThreshold(canvas);
+ initializeRects(renderer->getViewportHeight(), renderer->getViewportWidth());
+ drawGraph(renderer);
+ drawThreshold(renderer);
}
}
@@ -194,27 +198,26 @@
}
}
-void FrameInfoVisualizer::drawGraph(OpenGLRenderer* canvas) {
+void FrameInfoVisualizer::drawGraph(ContentRenderer* renderer) {
SkPaint paint;
for (size_t i = 0; i < Bar.size(); i++) {
nextBarSegment(Bar[i].start, Bar[i].end);
paint.setColor(Bar[i].color & BAR_FAST_MASK);
- canvas->drawRects(mFastRects.get(), mNumFastRects * 4, &paint);
+ renderer->drawRects(mFastRects.get(), mNumFastRects * 4, &paint);
paint.setColor(Bar[i].color & BAR_JANKY_MASK);
- canvas->drawRects(mJankyRects.get(), mNumJankyRects * 4, &paint);
+ renderer->drawRects(mJankyRects.get(), mNumJankyRects * 4, &paint);
}
}
-void FrameInfoVisualizer::drawThreshold(OpenGLRenderer* canvas) {
+void FrameInfoVisualizer::drawThreshold(ContentRenderer* renderer) {
SkPaint paint;
paint.setColor(THRESHOLD_COLOR);
- paint.setStrokeWidth(mThresholdStroke);
-
- float pts[4];
- pts[0] = 0.0f;
- pts[1] = pts[3] = canvas->getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
- pts[2] = canvas->getViewportWidth();
- canvas->drawLines(pts, 4, &paint);
+ float yLocation = renderer->getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
+ renderer->drawRect(0.0f,
+ yLocation - mThresholdStroke/2,
+ renderer->getViewportWidth(),
+ yLocation + mThresholdStroke/2,
+ &paint);
}
bool FrameInfoVisualizer::consumeProperties() {
diff --git a/libs/hwui/FrameInfoVisualizer.h b/libs/hwui/FrameInfoVisualizer.h
index cf877c4..83adf19 100644
--- a/libs/hwui/FrameInfoVisualizer.h
+++ b/libs/hwui/FrameInfoVisualizer.h
@@ -28,7 +28,13 @@
namespace android {
namespace uirenderer {
+#if HWUI_NEW_OPS
+class BakedOpRenderer;
+typedef BakedOpRenderer ContentRenderer;
+#else
class OpenGLRenderer;
+typedef OpenGLRenderer ContentRenderer;
+#endif
// TODO: This is a bit awkward as it needs to match the thing in CanvasContext
// A better abstraction here would be nice but iterators are painful
@@ -46,7 +52,7 @@
void setDensity(float density);
void unionDirty(SkRect* dirty);
- void draw(OpenGLRenderer* canvas);
+ void draw(ContentRenderer* renderer);
void dumpData(int fd);
@@ -56,8 +62,8 @@
void initializeRects(const int baseline, const int width);
void nextBarSegment(FrameInfoIndex start, FrameInfoIndex end);
- void drawGraph(OpenGLRenderer* canvas);
- void drawThreshold(OpenGLRenderer* canvas);
+ void drawGraph(ContentRenderer* renderer);
+ void drawThreshold(ContentRenderer* renderer);
inline float durationMS(size_t index, FrameInfoIndex start, FrameInfoIndex end) {
float duration = mFrameSource[index].duration(start, end) * 0.000001f;
diff --git a/libs/hwui/LayerBuilder.cpp b/libs/hwui/LayerBuilder.cpp
index bc39621..c5af279 100644
--- a/libs/hwui/LayerBuilder.cpp
+++ b/libs/hwui/LayerBuilder.cpp
@@ -140,7 +140,10 @@
// Identical round rect clip state means both ops will clip in the same way, or not at all.
// As the state objects are const, we can compare their pointers to determine mergeability
if (lhs->roundRectClipState != rhs->roundRectClipState) return false;
- if (lhs->projectionPathMask != rhs->projectionPathMask) return false;
+
+ // Local masks prevent merge, since they're potentially in different coordinate spaces
+ if (lhs->computedState.localProjectionPathMask
+ || rhs->computedState.localProjectionPathMask) return false;
/* Clipping compatibility check
*
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index b7a5923..7693fdc 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1148,7 +1148,9 @@
// always store/restore, since these are just pointers
state.mRoundRectClipState = currentSnapshot()->roundRectClipState;
+#if !HWUI_NEW_OPS
state.mProjectionPathMask = currentSnapshot()->projectionPathMask;
+#endif
return false;
}
@@ -1156,7 +1158,9 @@
setGlobalMatrix(state.mMatrix);
writableSnapshot()->alpha = state.mAlpha;
writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
+#if !HWUI_NEW_OPS
writableSnapshot()->projectionPathMask = state.mProjectionPathMask;
+#endif
if (state.mClipValid && !skipClipRestore) {
writableSnapshot()->setClip(state.mClip.left, state.mClip.top,
@@ -1833,6 +1837,7 @@
path.addCircle(x, y, radius);
}
+#if !HWUI_NEW_OPS
if (CC_UNLIKELY(currentSnapshot()->projectionPathMask != nullptr)) {
// mask ripples with projection mask
SkPath maskPath = *(currentSnapshot()->projectionPathMask->projectionMask);
@@ -1852,6 +1857,7 @@
// in local space. Note that this can create CCW paths.
Op(path, maskPath, kIntersect_SkPathOp, &path);
}
+#endif
drawConvexPath(path, p);
}
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/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 27fea1f..cf5e69a 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -146,6 +146,9 @@
}
void Snapshot::buildScreenSpaceTransform(Matrix4* outTransform) const {
+#if HWUI_NEW_OPS
+ LOG_ALWAYS_FATAL("not supported - not needed by new ops");
+#else
// build (reverse ordered) list of the stack of snapshots, terminated with a NULL
Vector<const Snapshot*> snapshotList;
snapshotList.push(nullptr);
@@ -171,6 +174,7 @@
outTransform->multiply(*(current->transform));
}
}
+#endif
}
///////////////////////////////////////////////////////////////////////////////
@@ -223,15 +227,19 @@
}
void Snapshot::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) {
+#if HWUI_NEW_OPS
+ // TODO: remove allocator param for HWUI_NEW_OPS
+ projectionPathMask = path;
+#else
if (path) {
ProjectionPathMask* mask = new (allocator) ProjectionPathMask;
mask->projectionMask = path;
buildScreenSpaceTransform(&(mask->projectionMaskTransform));
-
projectionPathMask = mask;
} else {
projectionPathMask = nullptr;
}
+#endif
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index b03643f..3a01d04 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -63,6 +63,7 @@
float radius;
};
+// TODO: remove for HWUI_NEW_OPS
class ProjectionPathMask {
public:
static void* operator new(size_t size) = delete;
@@ -219,6 +220,7 @@
* Fills outTransform with the current, total transform to screen space,
* across layer boundaries.
*/
+ // TODO: remove for HWUI_NEW_OPS
void buildScreenSpaceTransform(Matrix4* outTransform) const;
/**
@@ -294,9 +296,13 @@
const RoundRectClipState* roundRectClipState;
/**
- * Current projection masking path - used exclusively to mask tessellated circles.
+ * Current projection masking path - used exclusively to mask projected, tessellated circles.
*/
+#if HWUI_NEW_OPS
+ const SkPath* projectionPathMask;
+#else
const ProjectionPathMask* projectionPathMask;
+#endif
void dump() const;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 249d83f..a496b49 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -348,12 +348,26 @@
FrameBuilder frameBuilder(mLayerUpdateQueue, dirty, frame.width(), frame.height(),
mRenderNodes, mLightGeometry, mContentDrawBounds, &Caches::getInstance());
mLayerUpdateQueue.clear();
- BakedOpRenderer renderer(Caches::getInstance(), mRenderThread.renderState(),
+ auto&& caches = Caches::getInstance();
+ BakedOpRenderer renderer(caches, mRenderThread.renderState(),
mOpaque, mLightInfo);
- // TODO: profiler().draw(mCanvas);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
+ profiler().draw(&renderer);
bool drew = renderer.didDraw();
+ // post frame cleanup
+ caches.clearGarbage();
+ caches.pathCache.trim();
+ caches.tessellationCache.trim();
+
+#if DEBUG_MEMORY_USAGE
+ mCaches.dumpMemoryUsage();
+#else
+ if (CC_UNLIKELY(Properties::debugLevel & kDebugMemory)) {
+ caches.dumpMemoryUsage();
+ }
+#endif
+
#else
mCanvas->prepareDirty(frame.width(), frame.height(),
dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom, mOpaque);
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 f86898f..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 {
@@ -990,21 +989,26 @@
EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
expectedMatrix.loadIdentity();
+ EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
break;
case 1:
EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
- expectedMatrix.loadTranslate(50, 50, 0); // TODO: should scroll be respected here?
+ expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0);
+ ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
+ EXPECT_EQ(Rect(-35, -30, 45, 50),
+ Rect(state.computedState.localProjectionPathMask->getBounds()));
break;
case 2:
EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
+ EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
break;
default:
ADD_FAILURE();
}
- EXPECT_MATRIX_APPROX_EQ(expectedMatrix, state.computedState.transform);
+ EXPECT_EQ(expectedMatrix, state.computedState.transform);
}
};
@@ -1045,6 +1049,9 @@
});
auto parent = TestUtils::createNode(0, 0, 100, 100,
[&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
+ // Set a rect outline for the projecting ripple to be masked against.
+ properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
+
canvas.save(SaveFlags::MatrixClip);
canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
canvas.drawRenderNode(receiverBackground.get());
@@ -1059,6 +1066,145 @@
EXPECT_EQ(3, renderer.getIndex());
}
+RENDERTHREAD_TEST(FrameBuilder, projectionHwLayer) {
+ static const int scrollX = 5;
+ static const int scrollY = 10;
+ class ProjectionHwLayerTestRenderer : public TestRendererBase {
+ public:
+ void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
+ EXPECT_EQ(0, mIndex++);
+ }
+ void onArcOp(const ArcOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(1, mIndex++);
+ ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
+ }
+ void endLayer() override {
+ EXPECT_EQ(2, mIndex++);
+ }
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(3, mIndex++);
+ ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
+ }
+ void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(4, mIndex++);
+ ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
+ Matrix4 expected;
+ expected.loadTranslate(100 - scrollX, 100 - scrollY, 0);
+ EXPECT_EQ(expected, state.computedState.transform);
+ EXPECT_EQ(Rect(-85, -80, 295, 300),
+ Rect(state.computedState.localProjectionPathMask->getBounds()));
+ }
+ void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(5, mIndex++);
+ ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
+ }
+ };
+ auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
+ [](RenderProperties& properties, RecordingCanvas& canvas) {
+ properties.setProjectionReceiver(true);
+ // scroll doesn't apply to background, so undone via translationX/Y
+ // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
+ properties.setTranslationX(scrollX);
+ properties.setTranslationY(scrollY);
+
+ canvas.drawRect(0, 0, 400, 400, SkPaint());
+ });
+ auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
+ [](RenderProperties& properties, RecordingCanvas& canvas) {
+ properties.setProjectBackwards(true);
+ properties.setClipToBounds(false);
+ canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
+ });
+ auto child = TestUtils::createNode(100, 100, 300, 300,
+ [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
+ properties.mutateLayerProperties().setType(LayerType::RenderLayer);
+ canvas.drawRenderNode(projectingRipple.get());
+ canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint());
+ });
+ auto parent = TestUtils::createNode(0, 0, 400, 400,
+ [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
+ // Set a rect outline for the projecting ripple to be masked against.
+ properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
+ canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
+ canvas.drawRenderNode(receiverBackground.get());
+ canvas.drawRenderNode(child.get());
+ });
+
+ OffscreenBuffer** layerHandle = child->getLayerHandle();
+
+ // create RenderNode's layer here in same way prepareTree would, setting windowTransform
+ OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200, 200);
+ Matrix4 windowTransform;
+ windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin
+ layer.setWindowTransform(windowTransform);
+ *layerHandle = &layer;
+
+ auto syncedList = TestUtils::createSyncedNodeList(parent);
+ LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+ layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(200, 200));
+ FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
+ syncedList, sLightGeometry, nullptr);
+ ProjectionHwLayerTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(6, renderer.getIndex());
+
+ // clean up layer pointer, so we can safely destruct RenderNode
+ *layerHandle = nullptr;
+}
+
+RENDERTHREAD_TEST(FrameBuilder, projectionChildScroll) {
+ static const int scrollX = 500000;
+ static const int scrollY = 0;
+ class ProjectionChildScrollTestRenderer : public TestRendererBase {
+ public:
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(0, mIndex++);
+ EXPECT_TRUE(state.computedState.transform.isIdentity());
+ }
+ void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(1, mIndex++);
+ ASSERT_NE(nullptr, state.computedState.clipState);
+ ASSERT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
+ ASSERT_EQ(Rect(400, 400), state.computedState.clipState->rect);
+ EXPECT_TRUE(state.computedState.transform.isIdentity());
+ }
+ };
+ auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
+ [](RenderProperties& properties, RecordingCanvas& canvas) {
+ properties.setProjectionReceiver(true);
+ canvas.drawRect(0, 0, 400, 400, SkPaint());
+ });
+ auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
+ [](RenderProperties& properties, RecordingCanvas& canvas) {
+ // scroll doesn't apply to background, so undone via translationX/Y
+ // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
+ properties.setTranslationX(scrollX);
+ properties.setTranslationY(scrollY);
+ properties.setProjectBackwards(true);
+ properties.setClipToBounds(false);
+ canvas.drawOval(0, 0, 200, 200, SkPaint());
+ });
+ auto child = TestUtils::createNode(0, 0, 400, 400,
+ [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
+ // Record time clip will be ignored by projectee
+ canvas.clipRect(100, 100, 300, 300, SkRegion::kIntersect_Op);
+
+ canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
+ canvas.drawRenderNode(projectingRipple.get());
+ });
+ auto parent = TestUtils::createNode(0, 0, 400, 400,
+ [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
+ canvas.drawRenderNode(receiverBackground.get());
+ canvas.drawRenderNode(child.get());
+ });
+
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
+ TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
+ ProjectionChildScrollTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(2, renderer.getIndex());
+}
+
// creates a 100x100 shadow casting node with provided translationZ
static sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
return TestUtils::createNode(0, 0, 100, 100,
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..69d4487 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:
@@ -2729,13 +2730,16 @@
* this abstract class and register it with
* {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)}
* to be notified.
- * Use {@link AudioManager#getActiveRecordConfigurations()} to query the current configuration.
+ * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current
+ * configuration.
*/
public static abstract class AudioRecordingCallback {
/**
* Called whenever the device recording configuration has changed.
+ * @param configs array containing the results of
+ * {@link AudioManager#getActiveRecordingConfigurations()}.
*/
- public void onRecordConfigChanged() {}
+ public void onRecordConfigChanged(AudioRecordingConfiguration[] configs) {}
}
private static class AudioRecordingCallbackInfo {
@@ -2747,6 +2751,17 @@
}
}
+ private final static class RecordConfigChangeCallbackData {
+ final AudioRecordingCallback mCb;
+ final AudioRecordingConfiguration[] mConfigs;
+
+ RecordConfigChangeCallbackData(AudioRecordingCallback cb,
+ AudioRecordingConfiguration[] configs) {
+ mCb = cb;
+ mConfigs = configs;
+ }
+ }
+
/**
* Register a callback to be notified of audio recording changes through
* {@link AudioRecordingCallback}
@@ -2824,10 +2839,10 @@
* @return a non-null array of recording configurations. An array of length 0 indicates there is
* no recording active when queried.
*/
- public @NonNull AudioRecordConfiguration[] getActiveRecordConfigurations() {
+ public @NonNull AudioRecordingConfiguration[] getActiveRecordingConfigurations() {
final IAudioService service = getService();
try {
- return service.getActiveRecordConfigurations();
+ return service.getActiveRecordingConfigurations();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2882,14 +2897,15 @@
private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
- public void dispatchRecordingConfigChange() {
+ public void dispatchRecordingConfigChange(AudioRecordingConfiguration[] 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.aidl b/media/java/android/media/AudioRecordingConfiguration.aidl
similarity index 93%
rename from media/java/android/media/AudioRecordConfiguration.aidl
rename to media/java/android/media/AudioRecordingConfiguration.aidl
index afe912b..c63d30b 100644
--- a/media/java/android/media/AudioRecordConfiguration.aidl
+++ b/media/java/android/media/AudioRecordingConfiguration.aidl
@@ -15,4 +15,4 @@
package android.media;
-parcelable AudioRecordConfiguration;
+parcelable AudioRecordingConfiguration;
diff --git a/media/java/android/media/AudioRecordConfiguration.java b/media/java/android/media/AudioRecordingConfiguration.java
similarity index 73%
rename from media/java/android/media/AudioRecordConfiguration.java
rename to media/java/android/media/AudioRecordingConfiguration.java
index 2fc8ee8..cd6f95a 100644
--- a/media/java/android/media/AudioRecordConfiguration.java
+++ b/media/java/android/media/AudioRecordingConfiguration.java
@@ -16,21 +16,24 @@
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;
/**
- * The AudioRecordConfiguration class collects the information describing an audio recording
+ * The AudioRecordingConfiguration class collects the information describing an audio recording
* session. This information is returned through the
- * {@link AudioManager#getActiveRecordConfigurations()} method.
+ * {@link AudioManager#getActiveRecordingConfigurations()} method.
*
*/
-public final class AudioRecordConfiguration implements Parcelable {
- private final static String TAG = new String("AudioRecordConfiguration");
+public final class AudioRecordingConfiguration implements Parcelable {
+ private final static String TAG = new String("AudioRecordingConfiguration");
private final int mSessionId;
@@ -44,7 +47,7 @@
/**
* @hide
*/
- public AudioRecordConfiguration(int session, int source, AudioFormat devFormat,
+ public AudioRecordingConfiguration(int session, int source, AudioFormat devFormat,
AudioFormat clientFormat, int patchHandle) {
mSessionId = session;
mClientSource = source;
@@ -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()}.
@@ -120,18 +136,18 @@
return null;
}
- public static final Parcelable.Creator<AudioRecordConfiguration> CREATOR
- = new Parcelable.Creator<AudioRecordConfiguration>() {
+ public static final Parcelable.Creator<AudioRecordingConfiguration> CREATOR
+ = new Parcelable.Creator<AudioRecordingConfiguration>() {
/**
- * Rebuilds an AudioRecordConfiguration previously stored with writeToParcel().
- * @param p Parcel object to read the AudioRecordConfiguration from
- * @return a new AudioRecordConfiguration created from the data in the parcel
+ * Rebuilds an AudioRecordingConfiguration previously stored with writeToParcel().
+ * @param p Parcel object to read the AudioRecordingConfiguration from
+ * @return a new AudioRecordingConfiguration created from the data in the parcel
*/
- public AudioRecordConfiguration createFromParcel(Parcel p) {
- return new AudioRecordConfiguration(p);
+ public AudioRecordingConfiguration createFromParcel(Parcel p) {
+ return new AudioRecordingConfiguration(p);
}
- public AudioRecordConfiguration[] newArray(int size) {
- return new AudioRecordConfiguration[size];
+ public AudioRecordingConfiguration[] newArray(int size) {
+ return new AudioRecordingConfiguration[size];
}
};
@@ -154,7 +170,7 @@
dest.writeInt(mPatchHandle);
}
- private AudioRecordConfiguration(Parcel in) {
+ private AudioRecordingConfiguration(Parcel in) {
mSessionId = in.readInt();
mClientSource = in.readInt();
mClientFormat = AudioFormat.CREATOR.createFromParcel(in);
@@ -165,9 +181,9 @@
@Override
public boolean equals(Object o) {
if (this == o) return true;
- if (o == null || !(o instanceof AudioRecordConfiguration)) return false;
+ if (o == null || !(o instanceof AudioRecordingConfiguration)) return false;
- AudioRecordConfiguration that = (AudioRecordConfiguration) o;
+ AudioRecordingConfiguration that = (AudioRecordingConfiguration) o;
return ((mSessionId == that.mSessionId)
&& (mClientSource == that.mClientSource)
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 987a8b6..97f670b 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -20,7 +20,7 @@
import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
import android.media.AudioAttributes;
-import android.media.AudioRecordConfiguration;
+import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioRoutesObserver;
@@ -164,5 +164,5 @@
oneway void unregisterRecordingCallback(in IRecordingConfigDispatcher rcdb);
- AudioRecordConfiguration[] getActiveRecordConfigurations();
+ AudioRecordingConfiguration[] getActiveRecordingConfigurations();
}
diff --git a/media/java/android/media/IRecordingConfigDispatcher.aidl b/media/java/android/media/IRecordingConfigDispatcher.aidl
index a5eb8b9f..e803283 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.AudioRecordingConfiguration;
+
/**
* AIDL for the RecordingActivity monitor in AudioService to signal audio recording updates.
*
@@ -23,6 +25,6 @@
*/
oneway interface IRecordingConfigDispatcher {
- void dispatchRecordingConfigChange();
+ void dispatchRecordingConfigChange(in AudioRecordingConfiguration[] configs);
}
diff --git a/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl
index 8091421..4b1e39f 100644
--- a/media/java/android/media/IRingtonePlayer.aidl
+++ b/media/java/android/media/IRingtonePlayer.aidl
@@ -18,6 +18,7 @@
import android.media.AudioAttributes;
import android.net.Uri;
+import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
/**
@@ -36,4 +37,6 @@
/** Return the title of the media. */
String getTitle(in Uri uri);
+
+ ParcelFileDescriptor openRingtone(in Uri uri);
}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 4c6f0e6..c73cad4 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -2074,6 +2074,16 @@
*/
public static final int ERROR_SESSION_NOT_OPENED = 5;
+ /**
+ * This indicates that an operation was attempted that could not be
+ * supported by the crypto system of the device in its current
+ * configuration. It may occur when the license policy requires
+ * device security features that aren't supported by the device,
+ * or due to an internal error in the crypto system that prevents
+ * the specified security policy from being met.
+ */
+ public static final int ERROR_UNSUPPORTED_OPERATION = 6;
+
/** @hide */
@IntDef({
ERROR_NO_KEY,
@@ -2081,6 +2091,7 @@
ERROR_RESOURCE_BUSY,
ERROR_INSUFFICIENT_OUTPUT_PROTECTION,
ERROR_SESSION_NOT_OPENED,
+ ERROR_UNSUPPORTED_OPERATION
})
@Retention(RetentionPolicy.SOURCE)
public @interface CryptoErrorCode {}
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index b339925..177344a 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -28,6 +28,8 @@
import android.net.Uri;
import android.os.IBinder;
+import com.android.internal.util.Preconditions;
+
import java.io.FileDescriptor;
import java.io.IOException;
import java.lang.annotation.Retention;
@@ -189,6 +191,26 @@
}
/**
+ * Sets the data source (AssetFileDescriptor) to use. It is the caller's
+ * responsibility to close the file descriptor. It is safe to do so as soon
+ * as this call returns.
+ *
+ * @param afd the AssetFileDescriptor for the file you want to extract from.
+ */
+ public final void setDataSource(@NonNull AssetFileDescriptor afd)
+ throws IOException, IllegalArgumentException, IllegalStateException {
+ Preconditions.checkNotNull(afd);
+ // Note: using getDeclaredLength so that our behavior is the same
+ // as previous versions when the content provider is returning
+ // a full file.
+ if (afd.getDeclaredLength() < 0) {
+ setDataSource(afd.getFileDescriptor());
+ } else {
+ setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength());
+ }
+ }
+
+ /**
* Sets the data source (FileDescriptor) to use. It is the caller's responsibility
* to close the file descriptor. It is safe to do so as soon as this call returns.
*
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/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index 39bcef5..722605f 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -16,6 +16,7 @@
package android.media;
import android.annotation.NonNull;
+import android.annotation.StringDef;
import android.content.ContentResolver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -30,6 +31,8 @@
import android.util.Log;
import android.util.SparseArray;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Set;
/**
@@ -39,6 +42,40 @@
private static final String TAG = "MediaMetadata";
/**
+ * @hide
+ */
+ @StringDef({METADATA_KEY_TITLE, METADATA_KEY_ARTIST, METADATA_KEY_ALBUM, METADATA_KEY_AUTHOR,
+ METADATA_KEY_WRITER, METADATA_KEY_COMPOSER, METADATA_KEY_COMPILATION,
+ METADATA_KEY_DATE, METADATA_KEY_GENRE, METADATA_KEY_ALBUM_ARTIST, METADATA_KEY_ART_URI,
+ METADATA_KEY_ALBUM_ART_URI, METADATA_KEY_DISPLAY_TITLE, METADATA_KEY_DISPLAY_SUBTITLE,
+ METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_KEY_DISPLAY_ICON_URI,
+ METADATA_KEY_MEDIA_ID})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TextKey {}
+
+ /**
+ * @hide
+ */
+ @StringDef({METADATA_KEY_DURATION, METADATA_KEY_YEAR, METADATA_KEY_TRACK_NUMBER,
+ METADATA_KEY_NUM_TRACKS, METADATA_KEY_DISC_NUMBER})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LongKey {}
+
+ /**
+ * @hide
+ */
+ @StringDef({METADATA_KEY_ART, METADATA_KEY_ALBUM_ART, METADATA_KEY_DISPLAY_ICON})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface BitmapKey {}
+
+ /**
+ * @hide
+ */
+ @StringDef({METADATA_KEY_USER_RATING, METADATA_KEY_RATING})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RatingKey {}
+
+ /**
* The title of the media.
*/
public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
@@ -232,7 +269,7 @@
*/
public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
- private static final String[] PREFERRED_DESCRIPTION_ORDER = {
+ private static final @TextKey String[] PREFERRED_DESCRIPTION_ORDER = {
METADATA_KEY_TITLE,
METADATA_KEY_ARTIST,
METADATA_KEY_ALBUM,
@@ -242,13 +279,13 @@
METADATA_KEY_COMPOSER
};
- private static final String[] PREFERRED_BITMAP_ORDER = {
+ private static final @BitmapKey String[] PREFERRED_BITMAP_ORDER = {
METADATA_KEY_DISPLAY_ICON,
METADATA_KEY_ART,
METADATA_KEY_ALBUM_ART
};
- private static final String[] PREFERRED_URI_ORDER = {
+ private static final @TextKey String[] PREFERRED_URI_ORDER = {
METADATA_KEY_DISPLAY_ICON_URI,
METADATA_KEY_ART_URI,
METADATA_KEY_ALBUM_ART_URI
@@ -349,7 +386,7 @@
* @param key The key the value is stored under
* @return a CharSequence value, or null
*/
- public CharSequence getText(String key) {
+ public CharSequence getText(@TextKey String key) {
return mBundle.getCharSequence(key);
}
@@ -362,7 +399,7 @@
* @param key The key the value is stored under
* @return a String value, or null
*/
- public String getString(String key) {
+ public String getString(@TextKey String key) {
CharSequence text = getText(key);
if (text != null) {
return text.toString();
@@ -377,7 +414,7 @@
* @param key The key the value is stored under
* @return a long value
*/
- public long getLong(String key) {
+ public long getLong(@LongKey String key) {
return mBundle.getLong(key, 0);
}
@@ -388,7 +425,7 @@
* @param key The key the value is stored under
* @return A {@link Rating} or null
*/
- public Rating getRating(String key) {
+ public Rating getRating(@RatingKey String key) {
Rating rating = null;
try {
rating = mBundle.getParcelable(key);
@@ -406,7 +443,7 @@
* @param key The key the value is stored under
* @return A {@link Bitmap} or null
*/
- public Bitmap getBitmap(String key) {
+ public Bitmap getBitmap(@BitmapKey String key) {
Bitmap bmp = null;
try {
bmp = mBundle.getParcelable(key);
@@ -612,7 +649,7 @@
* @param value The CharSequence value to store
* @return The Builder to allow chaining
*/
- public Builder putText(String key, CharSequence value) {
+ public Builder putText(@TextKey String key, CharSequence value) {
if (METADATA_KEYS_TYPE.containsKey(key)) {
if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
throw new IllegalArgumentException("The " + key
@@ -654,7 +691,7 @@
* @param value The String value to store
* @return The Builder to allow chaining
*/
- public Builder putString(String key, String value) {
+ public Builder putString(@TextKey String key, String value) {
if (METADATA_KEYS_TYPE.containsKey(key)) {
if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
throw new IllegalArgumentException("The " + key
@@ -681,7 +718,7 @@
* @param value The long value to store
* @return The Builder to allow chaining
*/
- public Builder putLong(String key, long value) {
+ public Builder putLong(@LongKey String key, long value) {
if (METADATA_KEYS_TYPE.containsKey(key)) {
if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_LONG) {
throw new IllegalArgumentException("The " + key
@@ -705,7 +742,7 @@
* @param value The Rating value to store
* @return The Builder to allow chaining
*/
- public Builder putRating(String key, Rating value) {
+ public Builder putRating(@RatingKey String key, Rating value) {
if (METADATA_KEYS_TYPE.containsKey(key)) {
if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_RATING) {
throw new IllegalArgumentException("The " + key
@@ -734,7 +771,7 @@
* @param value The Bitmap to store
* @return The Builder to allow chaining
*/
- public Builder putBitmap(String key, Bitmap value) {
+ public Builder putBitmap(@BitmapKey String key, Bitmap value) {
if (METADATA_KEYS_TYPE.containsKey(key)) {
if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) {
throw new IllegalArgumentException("The " + key
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/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index bcc2b406..d8e0d6d 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -1547,18 +1547,30 @@
private Object mTag;
+ /** @hide */
+ @IntDef({PLAYBACK_TYPE_LOCAL, PLAYBACK_TYPE_REMOTE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PlaybackType {}
+
/**
* The default playback type, "local", indicating the presentation of the media is happening
* on the same device (e.g. a phone, a tablet) as where it is controlled from.
* @see #getPlaybackType()
*/
public final static int PLAYBACK_TYPE_LOCAL = 0;
+
/**
* A playback type indicating the presentation of the media is happening on
* a different device (i.e. the remote device) than where it is controlled from.
* @see #getPlaybackType()
*/
public final static int PLAYBACK_TYPE_REMOTE = 1;
+
+ /** @hide */
+ @IntDef({PLAYBACK_VOLUME_FIXED,PLAYBACK_VOLUME_VARIABLE})
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface PlaybackVolume {}
+
/**
* Playback information indicating the playback volume is fixed, i.e. it cannot be
* controlled from this object. An example of fixed playback volume is a remote player,
@@ -1783,6 +1795,7 @@
* @return the type of playback associated with this route
* @see UserRouteInfo#setPlaybackType(int)
*/
+ @PlaybackType
public int getPlaybackType() {
return mPlaybackType;
}
@@ -1874,6 +1887,7 @@
* @return how volume is handling on the route
* @see UserRouteInfo#setVolumeHandling(int)
*/
+ @PlaybackVolume
public int getVolumeHandling() {
return mVolumeHandling;
}
@@ -2164,7 +2178,7 @@
* ({@link RouteInfo#PLAYBACK_TYPE_REMOTE}).
* @param type
*/
- public void setPlaybackType(int type) {
+ public void setPlaybackType(@RouteInfo.PlaybackType int type) {
if (mPlaybackType != type) {
mPlaybackType = type;
configureSessionVolume();
@@ -2177,7 +2191,7 @@
* ({@link RouteInfo#PLAYBACK_VOLUME_VARIABLE}).
* @param volumeHandling
*/
- public void setVolumeHandling(int volumeHandling) {
+ public void setVolumeHandling(@RouteInfo.PlaybackVolume int volumeHandling) {
if (mVolumeHandling != volumeHandling) {
mVolumeHandling = volumeHandling;
configureSessionVolume();
@@ -2268,7 +2282,8 @@
return;
}
if (mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) {
- int volumeControl = VolumeProvider.VOLUME_CONTROL_FIXED;
+ @VolumeProvider.ControlType int volumeControl =
+ VolumeProvider.VOLUME_CONTROL_FIXED;
switch (mVolumeHandling) {
case RemoteControlClient.PLAYBACK_VOLUME_VARIABLE:
volumeControl = VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
@@ -2294,7 +2309,8 @@
class SessionVolumeProvider extends VolumeProvider {
- public SessionVolumeProvider(int volumeControl, int maxVolume, int currentVolume) {
+ public SessionVolumeProvider(@VolumeProvider.ControlType int volumeControl,
+ int maxVolume, int currentVolume) {
super(volumeControl, maxVolume, currentVolume);
}
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 78f357f..5fd85d1 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1042,13 +1042,13 @@
if(needToSetSettings) {
if (notifications) {
- setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId);
+ setRingtoneIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId);
mDefaultNotificationSet = true;
} else if (ringtones) {
- setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId);
+ setRingtoneIfNotSet(Settings.System.RINGTONE, tableUri, rowId);
mDefaultRingtoneSet = true;
} else if (alarms) {
- setSettingIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId);
+ setRingtoneIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId);
mDefaultAlarmSet = true;
}
}
@@ -1063,18 +1063,18 @@
pathFilenameStart + filenameLength == path.length();
}
- private void setSettingIfNotSet(String settingName, Uri uri, long rowId) {
-
- if(wasSettingAlreadySet(settingName)) {
+ private void setRingtoneIfNotSet(String settingName, Uri uri, long rowId) {
+ if (wasRingtoneAlreadySet(settingName)) {
return;
}
ContentResolver cr = mContext.getContentResolver();
String existingSettingValue = Settings.System.getString(cr, settingName);
if (TextUtils.isEmpty(existingSettingValue)) {
- // Set the setting to the given URI
- Settings.System.putString(cr, settingName,
- ContentUris.withAppendedId(uri, rowId).toString());
+ final Uri settingUri = Settings.System.getUriFor(settingName);
+ final Uri ringtoneUri = ContentUris.withAppendedId(uri, rowId);
+ RingtoneManager.setActualDefaultRingtoneUri(mContext,
+ RingtoneManager.getDefaultType(settingUri), ringtoneUri);
}
Settings.System.putInt(cr, settingSetIndicatorName(settingName), 1);
}
@@ -1107,7 +1107,7 @@
return base + "_set";
}
- private boolean wasSettingAlreadySet(String name) {
+ private boolean wasRingtoneAlreadySet(String name) {
ContentResolver cr = mContext.getContentResolver();
String indicatorName = settingSetIndicatorName(name);
try {
@@ -1134,9 +1134,9 @@
selectionArgs = new String[] { "" };
}
- mDefaultRingtoneSet = wasSettingAlreadySet(Settings.System.RINGTONE);
- mDefaultNotificationSet = wasSettingAlreadySet(Settings.System.NOTIFICATION_SOUND);
- mDefaultAlarmSet = wasSettingAlreadySet(Settings.System.ALARM_ALERT);
+ mDefaultRingtoneSet = wasRingtoneAlreadySet(Settings.System.RINGTONE);
+ mDefaultNotificationSet = wasRingtoneAlreadySet(Settings.System.NOTIFICATION_SOUND);
+ mDefaultAlarmSet = wasRingtoneAlreadySet(Settings.System.ALARM_ALERT);
// Tell the provider to not delete the file.
// If the file is truly gone the delete is unnecessary, and we want to avoid
diff --git a/media/java/android/media/Rating.java b/media/java/android/media/Rating.java
index a518bb4..04d5364f 100644
--- a/media/java/android/media/Rating.java
+++ b/media/java/android/media/Rating.java
@@ -16,10 +16,14 @@
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;
+
/**
* A class to encapsulate rating information used as content metadata.
* A rating is defined by its rating style (see {@link #RATING_HEART},
@@ -32,6 +36,21 @@
private final static String TAG = "Rating";
/**
+ * @hide
+ */
+ @IntDef({RATING_NONE, RATING_HEART, RATING_THUMB_UP_DOWN, RATING_3_STARS, RATING_4_STARS,
+ RATING_5_STARS, RATING_PERCENTAGE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Style {}
+
+ /**
+ * @hide
+ */
+ @IntDef({RATING_3_STARS, RATING_4_STARS, RATING_5_STARS})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StarStyle {}
+
+ /**
* Indicates a rating style is not supported. A Rating will never have this
* type, but can be used by other classes to indicate they do not support
* Rating.
@@ -75,7 +94,7 @@
private final float mRatingValue;
- private Rating(int ratingStyle, float rating) {
+ private Rating(@Style int ratingStyle, float rating) {
mRatingStyle = ratingStyle;
mRatingValue = rating;
}
@@ -124,7 +143,7 @@
* or {@link #RATING_PERCENTAGE}.
* @return null if an invalid rating style is passed, a new Rating instance otherwise.
*/
- public static Rating newUnratedRating(int ratingStyle) {
+ public static Rating newUnratedRating(@Style int ratingStyle) {
switch(ratingStyle) {
case RATING_HEART:
case RATING_THUMB_UP_DOWN:
@@ -172,7 +191,7 @@
* @return null if the rating style is invalid, or the rating is out of range,
* a new Rating instance otherwise.
*/
- public static Rating newStarRating(int starRatingStyle, float starRating) {
+ public static Rating newStarRating(@StarStyle int starRatingStyle, float starRating) {
float maxRating = -1.0f;
switch(starRatingStyle) {
case RATING_3_STARS:
@@ -225,6 +244,7 @@
* {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
* or {@link #RATING_PERCENTAGE}.
*/
+ @Style
public int getRatingStyle() {
return mRatingStyle;
}
@@ -285,4 +305,4 @@
return mRatingValue;
}
}
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index feb490d..4977391 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -30,7 +30,9 @@
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
+import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.RemoteException;
import android.provider.MediaStore;
import android.provider.Settings;
import android.provider.Settings.System;
@@ -223,9 +225,9 @@
*/
public static final int URI_COLUMN_INDEX = 2;
- private Activity mActivity;
- private Context mContext;
-
+ private final Activity mActivity;
+ private final Context mContext;
+
private Cursor mCursor;
private int mType = TYPE_RINGTONE;
@@ -246,7 +248,8 @@
* @param activity The activity used to get a managed cursor.
*/
public RingtoneManager(Activity activity) {
- mContext = mActivity = activity;
+ mActivity = activity;
+ mContext = activity;
setType(mType);
}
@@ -258,6 +261,7 @@
* @param context The context to used to get a cursor.
*/
public RingtoneManager(Context context) {
+ mActivity = null;
mContext = context;
setType(mType);
}
@@ -271,7 +275,6 @@
* @see #EXTRA_RINGTONE_TYPE
*/
public void setType(int type) {
-
if (mCursor != null) {
throw new IllegalStateException(
"Setting filter columns should be done before querying for ringtones.");
@@ -656,18 +659,19 @@
* @see #getActualDefaultRingtoneUri(Context, int)
*/
public static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri) {
+ final ContentResolver resolver = context.getContentResolver();
+
String setting = getSettingForType(type);
if (setting == null) return;
- Settings.System.putString(context.getContentResolver(), setting,
+ Settings.System.putString(resolver, setting,
ringtoneUri != null ? ringtoneUri.toString() : null);
// Stream selected ringtone into cache so it's available for playback
// when CE storage is still locked
if (ringtoneUri != null) {
- final ContentResolver cr = context.getContentResolver();
final Uri cacheUri = getCacheForType(type);
- try (InputStream in = cr.openInputStream(ringtoneUri);
- OutputStream out = cr.openOutputStream(cacheUri)) {
+ try (InputStream in = openRingtone(context, ringtoneUri);
+ OutputStream out = resolver.openOutputStream(cacheUri)) {
Streams.copy(in, out);
} catch (IOException e) {
Log.w(TAG, "Failed to cache ringtone: " + e);
@@ -675,6 +679,28 @@
}
}
+ /**
+ * Try opening the given ringtone locally first, but failover to
+ * {@link IRingtonePlayer} if we can't access it directly. Typically happens
+ * when process doesn't hold
+ * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}.
+ */
+ private static InputStream openRingtone(Context context, Uri uri) throws IOException {
+ final ContentResolver resolver = context.getContentResolver();
+ try {
+ return resolver.openInputStream(uri);
+ } catch (SecurityException | IOException e) {
+ Log.w(TAG, "Failed to open directly; attempting failover: " + e);
+ final IRingtonePlayer player = context.getSystemService(AudioManager.class)
+ .getRingtonePlayer();
+ try {
+ return new ParcelFileDescriptor.AutoCloseInputStream(player.openRingtone(uri));
+ } catch (Exception e2) {
+ throw new IOException(e2);
+ }
+ }
+ }
+
private static String getSettingForType(int type) {
if ((type & TYPE_RINGTONE) != 0) {
return Settings.System.RINGTONE;
diff --git a/media/java/android/media/VolumeProvider.java b/media/java/android/media/VolumeProvider.java
index 5d1e004..1c017c5 100644
--- a/media/java/android/media/VolumeProvider.java
+++ b/media/java/android/media/VolumeProvider.java
@@ -15,8 +15,12 @@
*/
package android.media;
+import android.annotation.IntDef;
import android.media.session.MediaSession;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Handles requests to adjust or set the volume on a session. This is also used
* to push volume updates back to the session. The provider must call
@@ -26,6 +30,14 @@
* {@link MediaSession#setPlaybackToRemote}.
*/
public abstract class VolumeProvider {
+
+ /**
+ * @hide
+ */
+ @IntDef({VOLUME_CONTROL_FIXED, VOLUME_CONTROL_RELATIVE, VOLUME_CONTROL_ABSOLUTE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ControlType {}
+
/**
* The volume is fixed and can not be modified. Requests to change volume
* should be ignored.
@@ -61,7 +73,7 @@
* @param maxVolume The maximum allowed volume.
* @param currentVolume The current volume on the output.
*/
- public VolumeProvider(int volumeControl, int maxVolume, int currentVolume) {
+ public VolumeProvider(@ControlType int volumeControl, int maxVolume, int currentVolume) {
mControlType = volumeControl;
mMaxVolume = maxVolume;
mCurrentVolume = currentVolume;
@@ -72,6 +84,7 @@
*
* @return The volume control type for this volume provider
*/
+ @ControlType
public final int getVolumeControl() {
return mControlType;
}
@@ -145,4 +158,4 @@
public static abstract class Callback {
public abstract void onVolumeChanged(VolumeProvider volumeProvider);
}
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 9e67c15..3642155 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -633,7 +633,6 @@
return;
}
- List<MediaItem> data = list == null ? null : list.getList();
if (DBG) {
Log.d(TAG, "onLoadChildren for " + mServiceComponent + " id=" + parentId);
}
@@ -644,10 +643,19 @@
// Tell the app.
SubscriptionCallback subscriptionCallback = subscription.getCallback(options);
if (subscriptionCallback != null) {
+ List<MediaItem> data = list == null ? null : list.getList();
if (options == null) {
- subscriptionCallback.onChildrenLoaded(parentId, data);
+ if (data == null) {
+ subscriptionCallback.onError(parentId);
+ } else {
+ subscriptionCallback.onChildrenLoaded(parentId, data);
+ }
} else {
- subscriptionCallback.onChildrenLoaded(parentId, data, options);
+ if (data == null) {
+ subscriptionCallback.onError(parentId, options);
+ } else {
+ subscriptionCallback.onChildrenLoaded(parentId, data, options);
+ }
}
return;
}
@@ -848,21 +856,21 @@
* Called when the list of children is loaded or updated.
*
* @param parentId The media id of the parent media item.
- * @param children The children which were loaded, or null if the id is invalid.
+ * @param children The children which were loaded.
*/
- public void onChildrenLoaded(@NonNull String parentId, List<MediaItem> children) {
+ public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children) {
}
/**
* Called when the list of children is loaded or updated.
*
* @param parentId The media id of the parent media item.
- * @param children The children which were loaded, or null if the id is invalid.
+ * @param children The children which were loaded.
* @param options A bundle of service-specific arguments sent to the media
* browse service. The contents of this bundle may affect the
* information returned when browsing.
*/
- public void onChildrenLoaded(@NonNull String parentId, List<MediaItem> children,
+ public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children,
@NonNull Bundle options) {
}
@@ -1108,7 +1116,7 @@
}
}
mCallbacks.add(callback);
- mOptionsList.add(options);
+ mOptionsList.add(options == null ? null : new Bundle(options));
}
public boolean removeCallback(Bundle options) {
diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java
index 266b0d9..07c8ae8 100644
--- a/media/java/android/media/midi/MidiManager.java
+++ b/media/java/android/media/midi/MidiManager.java
@@ -186,8 +186,7 @@
try {
mService.registerListener(mToken, deviceListener);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in registerDeviceListener");
- return;
+ throw e.rethrowFromSystemServer();
}
mDeviceListeners.put(callback, deviceListener);
}
@@ -203,7 +202,7 @@
try {
mService.unregisterListener(mToken, deviceListener);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in unregisterDeviceListener");
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -217,8 +216,7 @@
try {
return mService.getDevices();
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in getDevices");
- return new MidiDeviceInfo[0];
+ throw e.rethrowFromSystemServer();
}
}
@@ -267,7 +265,7 @@
try {
mService.openDevice(mToken, deviceInfo, callback);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in openDevice");
+ throw e.rethrowFromSystemServer();
}
}
@@ -306,7 +304,7 @@
try {
mService.openBluetoothDevice(mToken, bluetoothDevice, callback);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in openDevice");
+ throw e.rethrowFromSystemServer();
}
}
@@ -326,8 +324,7 @@
}
return server;
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in createVirtualDevice");
- return null;
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 0bd1713..7f9653d 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -469,7 +469,7 @@
* <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
* </ul>
*/
- public void setRatingType(int type) {
+ public void setRatingType(@Rating.Style int type) {
try {
mBinder.setRatingType(type);
} catch (RemoteException e) {
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index c61d7ad..95cb8ae 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -154,8 +154,8 @@
metadata.getString(MediaMetadata.METADATA_KEY_WRITER));
}
if (metadata.containsKey(MediaMetadata.METADATA_KEY_YEAR)) {
- oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_YEAR),
- metadata.getString(MediaMetadata.METADATA_KEY_YEAR));
+ oldMetadata.putLong(String.valueOf(MediaMetadataRetriever.METADATA_KEY_YEAR),
+ metadata.getLong(MediaMetadata.METADATA_KEY_YEAR));
}
return oldMetadata;
}
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 1485cd7..8283c8b 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -16,6 +16,7 @@
package android.media.session;
import android.annotation.DrawableRes;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.media.RemoteControlClient;
import android.os.Bundle;
@@ -26,6 +27,9 @@
import java.util.ArrayList;
import java.util.List;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Playback state for a {@link MediaSession}. This includes a state like
* {@link PlaybackState#STATE_PLAYING}, the current playback position,
@@ -35,6 +39,17 @@
private static final String TAG = "PlaybackState";
/**
+ * @hide
+ */
+ @IntDef(flag=true, value={ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND,
+ ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING,
+ ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
+ ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
+ ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Actions {}
+
+ /**
* Indicates this session supports the stop command.
*
* @see Builder#setActions(long)
@@ -161,6 +176,15 @@
public static final long ACTION_PREPARE_FROM_URI = 1 << 17;
/**
+ * @hide
+ */
+ @IntDef({STATE_NONE, STATE_STOPPED, STATE_PAUSED, STATE_PLAYING, STATE_FAST_FORWARDING,
+ STATE_REWINDING, STATE_BUFFERING, STATE_ERROR, STATE_CONNECTING,
+ STATE_SKIPPING_TO_PREVIOUS, STATE_SKIPPING_TO_NEXT, STATE_SKIPPING_TO_QUEUE_ITEM})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface State {}
+
+ /**
* This is the default playback state and indicates that no media has been
* added yet, or the performer has been reset and has no content to play.
*
@@ -349,9 +373,11 @@
* <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
* </ul>
*/
+ @State
public int getState() {
return mState;
}
+
/**
* Get the current playback position in ms.
*/
@@ -403,6 +429,7 @@
* <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
* </ul>
*/
+ @Actions
public long getActions() {
return mActions;
}
@@ -866,7 +893,8 @@
* timebase that the position was updated at.
* @return this
*/
- public Builder setState(int state, long position, float playbackSpeed, long updateTime) {
+ public Builder setState(@State int state, long position, float playbackSpeed,
+ long updateTime) {
mState = state;
mPosition = position;
mUpdateTime = updateTime;
@@ -907,7 +935,7 @@
* normal playback.
* @return this
*/
- public Builder setState(int state, long position, float playbackSpeed) {
+ public Builder setState(@State int state, long position, float playbackSpeed) {
return setState(state, position, playbackSpeed, SystemClock.elapsedRealtime());
}
@@ -938,7 +966,7 @@
* @param actions The set of actions allowed.
* @return this
*/
- public Builder setActions(long actions) {
+ public Builder setActions(@Actions long actions) {
mActions = actions;
return this;
}
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index 4fd3310..fdd7fc2 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -69,6 +69,7 @@
try {
mSoundTriggerService.updateSoundModel(model.getGenericSoundModel());
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -81,7 +82,7 @@
return new Model(mSoundTriggerService.getSoundModel(
new ParcelUuid(soundModelId)));
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -92,6 +93,7 @@
try {
mSoundTriggerService.deleteSoundModel(new ParcelUuid(soundModelId));
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 63e3edc..7c9591d 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -349,12 +349,12 @@
/**
* Returns the number of tuners this TV input has.
*
- * <p>This method is valid only for the input of type {@link #TYPE_TUNER}.
+ * <p>This method is valid only for inputs of type {@link #TYPE_TUNER}. For inputs of other
+ * types, it returns 0.
*
* <p>Tuners correspond to physical/logical resources that allow reception of TV signal. Having
* <i>N</i> tuners means that the TV input is capable of receiving <i>N</i> different channels
* concurrently.
- *
*/
public int getTunerCount() {
return mTunerCount;
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 59dfbee..0b0306c 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -1111,7 +1111,7 @@
}
}
} catch (RemoteException e) {
- Log.e(TAG, "TvInputManager initialization failed", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1124,7 +1124,7 @@
try {
return mService.getTvInputList(mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1140,7 +1140,7 @@
try {
return mService.getTvInputInfo(inputId, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1157,7 +1157,7 @@
try {
mService.updateTvInputInfo(inputInfo, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException("Error trying to update " + inputInfo, e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1228,7 +1228,7 @@
try {
return mService.isParentalControlsEnabled(mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1245,7 +1245,7 @@
try {
mService.setParentalControlsEnabled(enabled, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1260,7 +1260,7 @@
try {
return mService.isRatingBlocked(rating.flattenToString(), mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1279,7 +1279,7 @@
}
return ratings;
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1297,7 +1297,7 @@
try {
mService.addBlockedRating(rating.flattenToString(), mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1315,7 +1315,7 @@
try {
mService.removeBlockedRating(rating.flattenToString(), mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1328,7 +1328,7 @@
try {
return mService.getTvContentRatingSystemList(mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1378,7 +1378,7 @@
try {
mService.createSession(mClient, inputId, isRecordingSession, seq, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1402,7 +1402,7 @@
try {
return mService.getAvailableTvStreamConfigList(inputId, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1420,7 +1420,7 @@
try {
return mService.captureFrame(inputId, surface, config, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1434,7 +1434,7 @@
try {
return mService.isSingleSessionActive(mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1448,7 +1448,7 @@
try {
return mService.getHardwareList();
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1478,7 +1478,7 @@
}
}, info, mUserId));
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1492,7 +1492,7 @@
try {
mService.releaseTvInputHardware(deviceId, hardware.getInterface(), mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1506,7 +1506,7 @@
try {
return mService.getDvbDeviceList();
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1529,7 +1529,7 @@
}
return mService.openDvbDevice(info, device);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1600,7 +1600,7 @@
try {
mService.releaseSession(mToken, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
releaseInternal();
@@ -1620,7 +1620,7 @@
try {
mService.setMainSession(mToken, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1638,7 +1638,7 @@
try {
mService.setSurface(mToken, surface, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1660,7 +1660,7 @@
try {
mService.dispatchSurfaceChanged(mToken, format, width, height, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1681,7 +1681,7 @@
}
mService.setVolume(mToken, volume, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1721,7 +1721,7 @@
try {
mService.tune(mToken, channelUri, params, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1738,7 +1738,7 @@
try {
mService.setCaptionEnabled(mToken, enabled, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1780,7 +1780,7 @@
try {
mService.selectTrack(mToken, type, trackId, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1928,7 +1928,7 @@
try {
mService.timeShiftPlay(mToken, recordedProgramUri, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1943,7 +1943,7 @@
try {
mService.timeShiftPause(mToken, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1958,7 +1958,7 @@
try {
mService.timeShiftResume(mToken, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1979,7 +1979,7 @@
try {
mService.timeShiftSeekTo(mToken, timeMs, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1996,7 +1996,7 @@
try {
mService.timeShiftSetPlaybackParams(mToken, params, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2013,7 +2013,7 @@
try {
mService.timeShiftEnablePositionTracking(mToken, enable, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2031,7 +2031,7 @@
try {
mService.startRecording(mToken, programHint, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2046,7 +2046,7 @@
try {
mService.stopRecording(mToken, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2069,7 +2069,7 @@
try {
mService.sendAppPrivateCommand(mToken, action, data, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2097,7 +2097,7 @@
try {
mService.createOverlayView(mToken, view.getWindowToken(), frame, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2115,7 +2115,7 @@
try {
mService.relayoutOverlayView(mToken, frame, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2130,7 +2130,7 @@
try {
mService.removeOverlayView(mToken, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2146,7 +2146,7 @@
try {
mService.unblockContent(mToken, unblockedRating.flattenToString(), mUserId);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index 6a44b1e..e623353 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -121,6 +121,8 @@
/**
* Returns the audio channel count. Valid only for {@link #TYPE_AUDIO} tracks.
+ *
+ * @throws IllegalStateException if not called on an audio track
*/
public final int getAudioChannelCount() {
if (mType != TYPE_AUDIO) {
@@ -131,6 +133,8 @@
/**
* Returns the audio sample rate, in the unit of Hz. Valid only for {@link #TYPE_AUDIO} tracks.
+ *
+ * @throws IllegalStateException if not called on an audio track
*/
public final int getAudioSampleRate() {
if (mType != TYPE_AUDIO) {
@@ -142,6 +146,8 @@
/**
* Returns the width of the video, in the unit of pixels. Valid only for {@link #TYPE_VIDEO}
* tracks.
+ *
+ * @throws IllegalStateException if not called on a video track
*/
public final int getVideoWidth() {
if (mType != TYPE_VIDEO) {
@@ -153,6 +159,8 @@
/**
* Returns the height of the video, in the unit of pixels. Valid only for {@link #TYPE_VIDEO}
* tracks.
+ *
+ * @throws IllegalStateException if not called on a video track
*/
public final int getVideoHeight() {
if (mType != TYPE_VIDEO) {
@@ -164,6 +172,8 @@
/**
* Returns the frame rate of the video, in the unit of fps (frames per second). Valid only for
* {@link #TYPE_VIDEO} tracks.
+ *
+ * @throws IllegalStateException if not called on a video track
*/
public final float getVideoFrameRate() {
if (mType != TYPE_VIDEO) {
@@ -175,6 +185,8 @@
/**
* Returns the pixel aspect ratio (the ratio of a pixel's width to its height) of the video.
* Valid only for {@link #TYPE_VIDEO} tracks.
+ *
+ * @throws IllegalStateException if not called on a video track
*/
public final float getVideoPixelAspectRatio() {
if (mType != TYPE_VIDEO) {
@@ -189,6 +201,8 @@
*
* <p>The complete list of values are defined in ETSI TS 101 154 V1.7.1 Annex B, ATSC A/53 Part
* 4 and SMPTE 2016-1-2007.
+ *
+ * @throws IllegalStateException if not called on a video track
*/
public final byte getVideoActiveFormatDescription() {
if (mType != TYPE_VIDEO) {
@@ -268,6 +282,8 @@
* @param type The type of the track.
* @param id The ID of the track that uniquely identifies the current track among all the
* other tracks in the same TV program.
+ * @throws IllegalArgumentException if the type is not any of {@link #TYPE_AUDIO},
+ * {@link #TYPE_VIDEO} and {@link #TYPE_SUBTITLE}
*/
public Builder(int type, @NonNull String id) {
if (type != TYPE_AUDIO
@@ -304,6 +320,7 @@
* Sets the audio channel count. Valid only for {@link #TYPE_AUDIO} tracks.
*
* @param audioChannelCount The audio channel count.
+ * @throws IllegalStateException if not called on an audio track
*/
public final Builder setAudioChannelCount(int audioChannelCount) {
if (mType != TYPE_AUDIO) {
@@ -318,6 +335,7 @@
* tracks.
*
* @param audioSampleRate The audio sample rate.
+ * @throws IllegalStateException if not called on an audio track
*/
public final Builder setAudioSampleRate(int audioSampleRate) {
if (mType != TYPE_AUDIO) {
@@ -332,6 +350,7 @@
* tracks.
*
* @param videoWidth The width of the video.
+ * @throws IllegalStateException if not called on a video track
*/
public final Builder setVideoWidth(int videoWidth) {
if (mType != TYPE_VIDEO) {
@@ -346,6 +365,7 @@
* tracks.
*
* @param videoHeight The height of the video.
+ * @throws IllegalStateException if not called on a video track
*/
public final Builder setVideoHeight(int videoHeight) {
if (mType != TYPE_VIDEO) {
@@ -360,6 +380,7 @@
* {@link #TYPE_VIDEO} tracks.
*
* @param videoFrameRate The frame rate of the video.
+ * @throws IllegalStateException if not called on a video track
*/
public final Builder setVideoFrameRate(float videoFrameRate) {
if (mType != TYPE_VIDEO) {
@@ -379,6 +400,7 @@
* pixel aspect ratio for most video formats.
*
* @param videoPixelAspectRatio The pixel aspect ratio of the video.
+ * @throws IllegalStateException if not called on a video track
*/
public final Builder setVideoPixelAspectRatio(float videoPixelAspectRatio) {
if (mType != TYPE_VIDEO) {
@@ -398,6 +420,7 @@
* 4 and SMPTE 2016-1-2007.
*
* @param videoActiveFormatDescription The AFD code of the video.
+ * @throws IllegalStateException if not called on a video track
*/
public final Builder setVideoActiveFormatDescription(byte videoActiveFormatDescription) {
if (mType != TYPE_VIDEO) {
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 480acd9..f593685 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -45,6 +45,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -120,8 +121,8 @@
* they are done. If more than one of those methods is called, an exception will
* be thrown.
*
- * @see MediaBrowserService#onLoadChildren
- * @see MediaBrowserService#onLoadItem
+ * @see #onLoadChildren
+ * @see #onLoadItem
*/
public class Result<T> {
private Object mDebug;
@@ -367,11 +368,16 @@
* {@link Result#detach result.detach} may be called before returning from
* this function, and then {@link Result#sendResult result.sendResult}
* 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. 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, or 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);
@@ -385,11 +391,16 @@
* {@link Result#detach result.detach} may be called before returning from
* this function, and then {@link Result#sendResult result.sendResult}
* 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. 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, or 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.
@@ -411,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, or 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);
@@ -630,6 +646,9 @@
private List<MediaBrowser.MediaItem> applyOptions(List<MediaBrowser.MediaItem> list,
final Bundle options) {
+ if (list == null) {
+ return null;
+ }
int page = options.getInt(MediaBrowser.EXTRA_PAGE, -1);
int pageSize = options.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
if (page == -1 && pageSize == -1) {
@@ -638,7 +657,7 @@
int fromIndex = pageSize * (page - 1);
int toIndex = fromIndex + pageSize;
if (page < 1 || pageSize < 1 || fromIndex >= list.size()) {
- return null;
+ return Collections.EMPTY_LIST;
}
if (toIndex > list.size()) {
toIndex = list.size();
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..810996e 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -65,6 +65,7 @@
jint cryptoErrorResourceBusy;
jint cryptoErrorInsufficientOutputProtection;
jint cryptoErrorSessionNotOpened;
+ jint cryptoErrorUnsupportedOperation;
} gCryptoErrorCodes;
static struct CodecActionCodes {
@@ -869,6 +870,10 @@
err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
defaultMsg = "Attempted to use a closed session";
break;
+ case ERROR_DRM_CANNOT_HANDLE:
+ err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
+ defaultMsg = "Operation not supported in this configuration";
+ break;
default: /* Other negative DRM error codes go out as is. */
break;
}
@@ -1302,7 +1307,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);
}
@@ -1770,6 +1778,11 @@
gCryptoErrorCodes.cryptoErrorSessionNotOpened =
env->GetStaticIntField(clazz.get(), field);
+ field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
+ CHECK(field != NULL);
+ gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
+ env->GetStaticIntField(clazz.get(), field);
+
clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
CHECK(clazz.get() != NULL);
field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
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/Android.mk b/packages/DocumentsUI/Android.mk
index 6dfc3bb..d5e48b5 100644
--- a/packages/DocumentsUI/Android.mk
+++ b/packages/DocumentsUI/Android.mk
@@ -38,5 +38,4 @@
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
-
-include $(LOCAL_PATH)/tests/Android.mk
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/DocumentsUI/perf-tests/Android.mk b/packages/DocumentsUI/perf-tests/Android.mk
new file mode 100644
index 0000000..11c163b
--- /dev/null
+++ b/packages/DocumentsUI/perf-tests/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+#LOCAL_SDK_VERSION := current
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+ $(call all-java-files-under, ../tests/src/com/android/documentsui/bots) \
+ ../tests/src/com/android/documentsui/ActivityTest.java \
+ ../tests/src/com/android/documentsui/DocumentsProviderHelper.java \
+ ../tests/src/com/android/documentsui/StubProvider.java
+
+LOCAL_JAVA_LIBRARIES := android-support-v4 android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ub-uiautomator
+
+LOCAL_PACKAGE_NAME := DocumentsUIPerfTests
+LOCAL_INSTRUMENTATION_FOR := DocumentsUI
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
diff --git a/packages/DocumentsUI/perf-tests/AndroidManifest.xml b/packages/DocumentsUI/perf-tests/AndroidManifest.xml
new file mode 100644
index 0000000..97353e7
--- /dev/null
+++ b/packages/DocumentsUI/perf-tests/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.documentsui.perftests">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <provider
+ android:name="com.android.documentsui.StressProvider"
+ android:authorities="com.android.documentsui.stressprovider"
+ android:exported="true"
+ android:grantUriPermissions="true"
+ android:permission="android.permission.MANAGE_DOCUMENTS"
+ android:enabled="true">
+ <intent-filter>
+ <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
+ </intent-filter>
+ </provider>
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.documentsui"
+ android:label="Performance tests for DocumentsUI" />
+
+</manifest>
diff --git a/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java
new file mode 100644
index 0000000..bf056f1
--- /dev/null
+++ b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.documentsui;
+
+import static com.android.documentsui.StressProvider.DEFAULT_AUTHORITY;
+import static com.android.documentsui.StressProvider.STRESS_ROOT_0_ID;
+import static com.android.documentsui.StressProvider.STRESS_ROOT_1_ID;
+
+import android.app.Activity;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import com.android.documentsui.model.RootInfo;
+import com.android.documentsui.EventListener;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+
+@LargeTest
+public class FilesActivityPerfTest extends ActivityTest<FilesActivity> {
+
+ // Constants starting with KEY_ are used to report metrics to APCT.
+ private static final String KEY_FILES_LISTED_PERFORMANCE_FIRST =
+ "files-listed-performance-first";
+
+ private static final String KEY_FILES_LISTED_PERFORMANCE_MEDIAN =
+ "files-listed-performance-median";
+
+ private static final String TESTED_URI =
+ "content://com.android.documentsui.stressprovider/document/STRESS_ROOT_1_DOC";
+
+ private static final int NUM_MEASUREMENTS = 10;
+
+ public FilesActivityPerfTest() {
+ super(FilesActivity.class);
+ }
+
+ @Override
+ protected RootInfo getInitialRoot() {
+ return rootDir0;
+ }
+
+ @Override
+ protected String getTestingProviderAuthority() {
+ return DEFAULT_AUTHORITY;
+ }
+
+ @Override
+ protected void setupTestingRoots() throws RemoteException {
+ rootDir0 = mDocsHelper.getRoot(STRESS_ROOT_0_ID);
+ rootDir1 = mDocsHelper.getRoot(STRESS_ROOT_1_ID);
+ }
+
+ @Override
+ public void initTestFiles() throws RemoteException {
+ // Nothing to create, already done by StressProvider.
+ }
+
+ public void testFilesListedPerformance() throws Exception {
+ final BaseActivity activity = getActivity();
+
+ final List<Long> measurements = new ArrayList<Long>();
+ EventListener listener;
+ for (int i = 0; i < 10; i++) {
+ final CountDownLatch signal = new CountDownLatch(1);
+ listener = new EventListener() {
+ @Override
+ public void onDirectoryNavigated(Uri uri) {
+ if (uri != null && TESTED_URI.equals(uri.toString())) {
+ mStartTime = System.currentTimeMillis();
+ } else {
+ mStartTime = -1;
+ }
+ }
+
+ @Override
+ public void onDirectoryLoaded(Uri uri) {
+ if (uri == null || !TESTED_URI.equals(uri.toString())) {
+ return;
+ }
+ assertTrue(mStartTime != -1);
+ getInstrumentation().waitForIdle(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(mStartTime != -1);
+ measurements.add(System.currentTimeMillis() - mStartTime);
+ signal.countDown();
+ }
+ });
+ }
+
+ private long mStartTime = -1;
+ };
+
+ try {
+ activity.addEventListener(listener);
+ bots.roots.openRoot(STRESS_ROOT_1_ID);
+ signal.await();
+ } finally {
+ activity.removeEventListener(listener);
+ }
+
+ assertEquals(i + 1, measurements.size());
+
+ // Go back to the empty root.
+ bots.roots.openRoot(STRESS_ROOT_0_ID);
+ }
+
+ assertEquals(NUM_MEASUREMENTS, measurements.size());
+
+ final Bundle status = new Bundle();
+ status.putDouble(KEY_FILES_LISTED_PERFORMANCE_FIRST, measurements.get(0));
+
+ final Long[] rawMeasurements = measurements.toArray(new Long[NUM_MEASUREMENTS]);
+ Arrays.sort(rawMeasurements);
+
+ final long median = rawMeasurements[NUM_MEASUREMENTS / 2 - 1];
+ status.putDouble(KEY_FILES_LISTED_PERFORMANCE_MEDIAN, median);
+
+ getInstrumentation().sendStatus(Activity.RESULT_OK, status);
+ }
+}
diff --git a/packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java
new file mode 100644
index 0000000..1bc802a
--- /dev/null
+++ b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java
@@ -0,0 +1,149 @@
+/*
+ * 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.documentsui;
+
+import android.content.Context;
+import android.content.pm.ProviderInfo;
+import android.database.Cursor;
+import android.database.MatrixCursor.RowBuilder;
+import android.database.MatrixCursor;
+import android.os.CancellationSignal;
+import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsProvider;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * Provider with thousands of files for testing loading time of directories in DocumentsUI.
+ * It doesn't support any file operations.
+ */
+public class StressProvider extends DocumentsProvider {
+
+ public static final String DEFAULT_AUTHORITY = "com.android.documentsui.stressprovider";
+
+ // Empty root.
+ public static final String STRESS_ROOT_0_ID = "STRESS_ROOT_0";
+
+ // Root with thousands of items.
+ public static final String STRESS_ROOT_1_ID = "STRESS_ROOT_1";
+
+ private static final String STRESS_ROOT_0_DOC_ID = "STRESS_ROOT_0_DOC";
+ private static final String STRESS_ROOT_1_DOC_ID = "STRESS_ROOT_1_DOC";
+
+ private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
+ Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_TITLE, Root.COLUMN_DOCUMENT_ID,
+ Root.COLUMN_AVAILABLE_BYTES
+ };
+ private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
+ Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, Document.COLUMN_DISPLAY_NAME,
+ Document.COLUMN_LAST_MODIFIED, Document.COLUMN_FLAGS, Document.COLUMN_SIZE,
+ };
+
+ private String mAuthority = DEFAULT_AUTHORITY;
+ private ArrayList<String> mIds = new ArrayList<>();
+
+ @Override
+ public void attachInfo(Context context, ProviderInfo info) {
+ mAuthority = info.authority;
+ super.attachInfo(context, info);
+ }
+
+ @Override
+ public boolean onCreate() {
+ mIds = new ArrayList();
+ for (int i = 0; i < 10000; i++) {
+ mIds.add(createRandomId(i));
+ }
+ mIds.add(STRESS_ROOT_0_DOC_ID);
+ mIds.add(STRESS_ROOT_1_DOC_ID);
+ return true;
+ }
+
+ @Override
+ public Cursor queryRoots(String[] projection) throws FileNotFoundException {
+ final MatrixCursor result = new MatrixCursor(DEFAULT_ROOT_PROJECTION);
+ includeRoot(result, STRESS_ROOT_0_ID, STRESS_ROOT_0_DOC_ID);
+ includeRoot(result, STRESS_ROOT_1_ID, STRESS_ROOT_1_DOC_ID);
+ return result;
+ }
+
+ @Override
+ public Cursor queryDocument(String documentId, String[] projection)
+ throws FileNotFoundException {
+ final MatrixCursor result = new MatrixCursor(DEFAULT_DOCUMENT_PROJECTION);
+ includeDocument(result, documentId);
+ return result;
+ }
+
+ @Override
+ public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder)
+ throws FileNotFoundException {
+ final MatrixCursor result = new MatrixCursor(DEFAULT_DOCUMENT_PROJECTION);
+ if (STRESS_ROOT_1_DOC_ID.equals(parentDocumentId)) {
+ for (String id : mIds) {
+ includeDocument(result, id);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public ParcelFileDescriptor openDocument(String docId, String mode, CancellationSignal signal)
+ throws FileNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ private void includeRoot(MatrixCursor result, String rootId, String docId) {
+ final RowBuilder row = result.newRow();
+ row.add(Root.COLUMN_ROOT_ID, rootId);
+ row.add(Root.COLUMN_FLAGS, 0);
+ row.add(Root.COLUMN_TITLE, rootId);
+ row.add(Root.COLUMN_DOCUMENT_ID, docId);
+ }
+
+ private void includeDocument(MatrixCursor result, String id) {
+ final RowBuilder row = result.newRow();
+ row.add(Document.COLUMN_DOCUMENT_ID, id);
+ row.add(Document.COLUMN_DISPLAY_NAME, id);
+ row.add(Document.COLUMN_SIZE, 0);
+ row.add(Document.COLUMN_MIME_TYPE, DocumentsContract.Document.MIME_TYPE_DIR);
+ row.add(Document.COLUMN_FLAGS, 0);
+ row.add(Document.COLUMN_LAST_MODIFIED, null);
+ }
+
+ private static String getDocumentIdForFile(File file) {
+ return file.getAbsolutePath();
+ }
+
+ private String createRandomId(int index) {
+ final Random random = new Random(index);
+ final StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < 20; i++) {
+ builder.append((char) (random.nextInt(96) + 32));
+ }
+ builder.append(index); // Append a number to guarantee uniqueness.
+ return builder.toString();
+ }
+}
diff --git a/packages/DocumentsUI/res/drawable/ic_breadcrumb_arrow_down.xml b/packages/DocumentsUI/res/drawable/ic_breadcrumb_arrow_down.xml
new file mode 100644
index 0000000..199a308
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_breadcrumb_arrow_down.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<rotate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromDegrees="90"
+ android:toDegrees="90"
+ android:pivotX="50%"
+ android:pivotY="50%"
+ android:drawable="@drawable/ic_breadcrumb_arrow">
+</rotate>
\ No newline at end of file
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..b65c5a0 100644
--- a/packages/DocumentsUI/res/layout/drawer_layout.xml
+++ b/packages/DocumentsUI/res/layout/drawer_layout.xml
@@ -46,6 +46,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
+ android:popupTheme="?actionBarPopupTheme"
+ android:background="@android:color/transparent"
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..deb0894 100644
--- a/packages/DocumentsUI/res/layout/fixed_layout.xml
+++ b/packages/DocumentsUI/res/layout/fixed_layout.xml
@@ -44,6 +44,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
+ android:popupTheme="?actionBarPopupTheme"
+ android:background="@android:color/transparent"
android:overlapAnchor="true" />
</com.android.documentsui.DocumentsToolbar>
diff --git a/packages/DocumentsUI/res/layout/item_root.xml b/packages/DocumentsUI/res/layout/item_root.xml
index ff80d07..816cb8a 100644
--- a/packages/DocumentsUI/res/layout/item_root.xml
+++ b/packages/DocumentsUI/res/layout/item_root.xml
@@ -27,8 +27,6 @@
<FrameLayout
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
- android:layout_marginStart="@dimen/root_icon_margin"
- android:layout_marginEnd="@dimen/root_icon_margin"
android:duplicateParentState="true">
<ImageView
@@ -55,7 +53,7 @@
android:singleLine="true"
android:ellipsize="end"
android:textAlignment="viewStart"
- android:textAppearance="@android:style/TextAppearance.Material.Body1"
+ android:textAppearance="@android:style/TextAppearance.Material.Menu"
android:textColor="@color/item_root_primary_text" />
<TextView
@@ -65,7 +63,7 @@
android:singleLine="true"
android:ellipsize="end"
android:textAlignment="viewStart"
- android:textAppearance="@android:style/TextAppearance.Material.Body1"
+ android:textAppearance="@android:style/TextAppearance.Material.Caption"
android:textColor="@color/item_root_primary_text" />
</LinearLayout>
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/item_subdir_title.xml b/packages/DocumentsUI/res/layout/item_subdir_title.xml
index de6c523..8d0d807 100644
--- a/packages/DocumentsUI/res/layout/item_subdir_title.xml
+++ b/packages/DocumentsUI/res/layout/item_subdir_title.xml
@@ -28,6 +28,7 @@
android:singleLine="true"
android:ellipsize="end"
android:textAlignment="viewStart"
+ android:drawablePadding="12dp"
+ android:drawableRight="@drawable/ic_breadcrumb_arrow_down"
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title" />
-
</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/single_pane_layout.xml b/packages/DocumentsUI/res/layout/single_pane_layout.xml
index 235d22d..7b7e229 100644
--- a/packages/DocumentsUI/res/layout/single_pane_layout.xml
+++ b/packages/DocumentsUI/res/layout/single_pane_layout.xml
@@ -43,6 +43,8 @@
android:id="@+id/stack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:popupTheme="?actionBarPopupTheme"
+ android:background="@android:color/transparent"
android:layout_marginStart="4dp"
android:overlapAnchor="true" />
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index 73571af..79f6fa9 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -84,10 +84,6 @@
android:showAsAction="never"
android:visible="false" />
<item
- android:id="@+id/menu_advanced"
- android:showAsAction="never"
- android:visible="false" />
- <item
android:id="@+id/menu_settings"
android:title="@string/menu_settings"
android:showAsAction="never"
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index 9c66502..d195ed5 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Deel via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopieer tans lêers"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Skuif tans lêers"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Vee tans lêers uit"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> oor"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Kopieer tans <xliff:g id="COUNT_1">%1$d</xliff:g> lêers.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sommige lêers is omgeskakel"</string>
<string name="allow" msgid="7225948811296386551">"Laat toe"</string>
<string name="deny" msgid="2081879885755434506">"Weier"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Vee <xliff:g id="COUNT_1">%1$d</xliff:g> lêers uit?</item>
+ <item quantity="one">Vee <xliff:g id="COUNT_0">%1$d</xliff:g> lêer uit?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index c255e36..d04980e 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"በሚከተለው በኩል ያጋሩ"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ፋይሎች በመገልበጥ ላይ"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ፋይሎችን በመውሰድ ላይ"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"ፋይሎችን በመሰረዝ ላይ"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ቀርቷል"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎች በመቅዳት ላይ።</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"አንዳንድ ፋይሎች ተለውጠዋል"</string>
<string name="allow" msgid="7225948811296386551">"ይፍቀዱ"</string>
<string name="deny" msgid="2081879885755434506">"ያስተባብሉ"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎች ይሰረዙ?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎች ይሰረዙ?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index 79c2c6a..157d07f 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -140,13 +140,12 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"تم تحويل بعض الملفات"</string>
<string name="allow" msgid="7225948811296386551">"السماح"</string>
<string name="deny" msgid="2081879885755434506">"رفض"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"هل تريد حذف الملفات؟"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="zero">هل تريد بالتأكيد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملف؟</item>
- <item quantity="two">هل تريد بالتأكيد حذف ملفين (<xliff:g id="COUNT_1">%1$d</xliff:g>)؟</item>
- <item quantity="few">هل تريد بالتأكيد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملفات؟</item>
- <item quantity="many">هل تريد بالتأكيد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملفًا؟</item>
- <item quantity="other">هل تريد بالتأكيد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملف؟</item>
- <item quantity="one">هل تريد بالتأكيد حذف <xliff:g id="COUNT_0">%1$d</xliff:g> ملف؟</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="zero">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملف؟</item>
+ <item quantity="two">هل تريد حذف ملفين (<xliff:g id="COUNT_1">%1$d</xliff:g>)؟</item>
+ <item quantity="few">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملفات؟</item>
+ <item quantity="many">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملفًا؟</item>
+ <item quantity="other">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملف؟</item>
+ <item quantity="one">هل تريد حذف <xliff:g id="COUNT_0">%1$d</xliff:g> ملف؟</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-az-rAZ/strings.xml b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
index 8ba9036..2e07260 100644
--- a/packages/DocumentsUI/res/values-az-rAZ/strings.xml
+++ b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bəzi fayllar konvertasiya edilib"</string>
<string name="allow" msgid="7225948811296386551">"İcazə verin"</string>
<string name="deny" msgid="2081879885755434506">"Rədd et"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"Fayllar silinsin?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> faylı silmək istədiyinizə əminsiniz?</item>
- <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> faylı silmək istədiyinizə əminsiniz?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> fayl silinsin?</item>
+ <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> fayl silinsin?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
index 81a4f9bd..457c3e7 100644
--- a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Delite preko"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopiranje datoteka"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Datoteke se premeštaju"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Datoteke se brišu"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Još <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke.</item>
@@ -120,7 +119,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke datoteke su konvertovane"</string>
<string name="allow" msgid="7225948811296386551">"Dozvoli"</string>
<string name="deny" msgid="2081879885755434506">"Odbij"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku?</item>
+ <item quantity="few">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
+ <item quantity="other">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index 7c096d9..c0fb178 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Споделяне чрез"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Файловете се копират"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Файловете се преместват"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Изтриване на файлове"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Оставащо време: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Копират се <xliff:g id="COUNT_1">%1$d</xliff:g> файла.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Някои файлове бяха преобразувани"</string>
<string name="allow" msgid="7225948811296386551">"Разрешаване"</string>
<string name="deny" msgid="2081879885755434506">"Отказване"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Искате ли да изтриете <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+ <item quantity="one">Искате ли да изтриете <xliff:g id="COUNT_0">%1$d</xliff:g> файл?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
index 6bbe95b..0c5e4cb 100644
--- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml
+++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"কিছু ফাইল রূপান্তরিত হয়েছে"</string>
<string name="allow" msgid="7225948811296386551">"অনুমতি দিন"</string>
<string name="deny" msgid="2081879885755434506">"আস্বীকার করুন"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"ফাইলগুলি মুছবেন?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="one">আপনি কি <xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মোছার বিষয়ে নিশ্চিত?</item>
- <item quantity="other">আপনি কি <xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মোছার বিষয়ে নিশ্চিত?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মুছবেন?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মুছবেন?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-bs-rBA/strings.xml b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
index 68a2b42..03387c3 100644
--- a/packages/DocumentsUI/res/values-bs-rBA/strings.xml
+++ b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Podijeli preko"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopiraju se fajlovi"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Premještanje fajlova"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Brisanje fajlova"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Još <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Kopira se <xliff:g id="COUNT_1">%1$d</xliff:g> fajl.</item>
@@ -120,7 +119,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke od datoteka su pretvorene"</string>
<string name="allow" msgid="7225948811296386551">"Dozvoli"</string>
<string name="deny" msgid="2081879885755434506">"Odbijte"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajl.</item>
+ <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajla.</item>
+ <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajlova.</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index e979b11..42eab75 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Comparteix mitjançant"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"S\'estan copiant fitxers"</string>
<string name="move_notification_title" msgid="6193835179777284805">"S\'estan movent fitxers"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Suprimint els fitxers"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Temps restant: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">S\'estan copiant <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"S\'han convertit alguns fitxers"</string>
<string name="allow" msgid="7225948811296386551">"Permet"</string>
<string name="deny" msgid="2081879885755434506">"Denega"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Vols suprimir <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers?</item>
+ <item quantity="one">Vols suprimir <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index 0f3b4e0..a9b6724 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Sdílet pomocí"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopírování souborů"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Přesouvání souborů"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Mazání souborů"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Zbývající čas: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="few">Kopírování <xliff:g id="COUNT_1">%1$d</xliff:g> souborů</item>
@@ -127,7 +126,10 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Některé soubory byly převedeny"</string>
<string name="allow" msgid="7225948811296386551">"Povolit"</string>
<string name="deny" msgid="2081879885755434506">"Odepřít"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="few">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> soubory?</item>
+ <item quantity="many">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> souboru?</item>
+ <item quantity="other">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> souborů?</item>
+ <item quantity="one">Smazat <xliff:g id="COUNT_0">%1$d</xliff:g> soubor?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index 3854f0f..661e81f 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Del via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopierer filer"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Flytter filer"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Filerne slettes"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> tilbage"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Kopierer <xliff:g id="COUNT_1">%1$d</xliff:g> filer.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Nogle filer er konverteret"</string>
<string name="allow" msgid="7225948811296386551">"Tillad"</string>
<string name="deny" msgid="2081879885755434506">"Afvis"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
+ <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index fd7f35c..ebbbf31 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Teilen über"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Dateien werden kopiert"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Dateien werden verschoben"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Dateien werden gelöscht"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Noch <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Dateien werden kopiert.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Einige Dateien wurden konvertiert"</string>
<string name="allow" msgid="7225948811296386551">"Zulassen"</string>
<string name="deny" msgid="2081879885755434506">"Ablehnen"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Möchtest du <xliff:g id="COUNT_1">%1$d</xliff:g> Dateien löschen?</item>
+ <item quantity="one">Möchtest du <xliff:g id="COUNT_0">%1$d</xliff:g> Datei löschen?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index 6257e17..39e6828 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Κοινή χρήση μέσω"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Αντιγραφή αρχείων"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Μετακίνηση αρχείων"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Διαγραφή αρχείων"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Απομένουν <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Αντιγραφή <xliff:g id="COUNT_1">%1$d</xliff:g> αρχείων.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Ορισμένα αρχεία μετατράπηκαν"</string>
<string name="allow" msgid="7225948811296386551">"Να επιτρέπεται"</string>
<string name="deny" msgid="2081879885755434506">"Άρνηση"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Να διαγραφούν <xliff:g id="COUNT_1">%1$d</xliff:g> αρχεία;</item>
+ <item quantity="one">Να διαγραφεί <xliff:g id="COUNT_0">%1$d</xliff:g> αρχείο;</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-en-rAU/strings.xml b/packages/DocumentsUI/res/values-en-rAU/strings.xml
index 82c5557..c18f1a5 100644
--- a/packages/DocumentsUI/res/values-en-rAU/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rAU/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
<string name="allow" msgid="7225948811296386551">"Allow"</string>
<string name="deny" msgid="2081879885755434506">"Deny"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"Delete files?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other">Are you sure you want to delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
- <item quantity="one">Are you sure you want to delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
+ <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index 82c5557..c18f1a5 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
<string name="allow" msgid="7225948811296386551">"Allow"</string>
<string name="deny" msgid="2081879885755434506">"Deny"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"Delete files?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other">Are you sure you want to delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
- <item quantity="one">Are you sure you want to delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
+ <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index 82c5557..c18f1a5 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
<string name="allow" msgid="7225948811296386551">"Allow"</string>
<string name="deny" msgid="2081879885755434506">"Deny"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"Delete files?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other">Are you sure you want to delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
- <item quantity="one">Are you sure you want to delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
+ <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index 29b9111..2808e5f 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Compartir mediante"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copiando archivos"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Moviendo archivos"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Borrando los archivos"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Faltan <xliff:g id="DURATION">%s</xliff:g>."</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Se convirtieron algunos archivos"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
<string name="deny" msgid="2081879885755434506">"Denegar"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos?</item>
+ <item quantity="one">¿Deseas borrar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index 02e6d74..c8dae74 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Compartir a través de"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copiando archivos"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Moviendo archivos"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Eliminando archivos"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Tiempo restante: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> archivos.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Se han convertido algunos archivos"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
<string name="deny" msgid="2081879885755434506">"Denegar"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">¿Eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos?</item>
+ <item quantity="one">¿Eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index 13a4bfa..5574954 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Mõned failid teisendati"</string>
<string name="allow" msgid="7225948811296386551">"Luba"</string>
<string name="deny" msgid="2081879885755434506">"Keela"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"Kas kustutada failid?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other">Kas soovite kindlasti <xliff:g id="COUNT_1">%1$d</xliff:g> faili kustutada?</item>
- <item quantity="one">Kas soovite kindlasti <xliff:g id="COUNT_0">%1$d</xliff:g> faili kustutada?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Kas kustutada <xliff:g id="COUNT_1">%1$d</xliff:g> faili?</item>
+ <item quantity="one">Kas kustutada <xliff:g id="COUNT_0">%1$d</xliff:g> fail?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml
index 125d899..0dc1cf8 100644
--- a/packages/DocumentsUI/res/values-eu-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Partekatu honen bidez:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Fitxategiak kopiatzen"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Fitxategiak mugitzea"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Fitxategiak ezabatzea"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Falta den denbora: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi kopiatzen.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Artxibo batzuk bihurtu dira"</string>
<string name="allow" msgid="7225948811296386551">"Onartu"</string>
<string name="deny" msgid="2081879885755434506">"Ukatu"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi ezabatu nahi dituzu?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi ezabatu nahi duzu?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index 997eea8..52d4910f 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"بعضی از فایلها تبدیل شدند"</string>
<string name="allow" msgid="7225948811296386551">"ارزیابیشده"</string>
<string name="deny" msgid="2081879885755434506">"اجازه ندارد"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"فایلها حذف شوند؟"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="one">مطمئنید میخواهید <xliff:g id="COUNT_1">%1$d</xliff:g> فایل را حذف کنید؟</item>
- <item quantity="other">مطمئنید میخواهید <xliff:g id="COUNT_1">%1$d</xliff:g> فایل را حذف کنید؟</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> فایل حذف شود؟</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فایل حذف شود؟</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index 0788598..6afbef2 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Jaa sovelluksessa"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopioidaan tiedostoja"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Siirretään tiedostoja"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Poistetaan tiedostoja"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> jäljellä"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Kopioidaan <xliff:g id="COUNT_1">%1$d</xliff:g> tiedostoa.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Joitakin tiedostoja muunnettiin."</string>
<string name="allow" msgid="7225948811296386551">"Salli"</string>
<string name="deny" msgid="2081879885755434506">"Kiellä"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Poistetaanko <xliff:g id="COUNT_1">%1$d</xliff:g> tiedostoa?</item>
+ <item quantity="one">Poistetaanko <xliff:g id="COUNT_0">%1$d</xliff:g> tiedosto?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index 6b4c7fd..2ec6773 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Partager par"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copie de fichiers..."</string>
<string name="move_notification_title" msgid="6193835179777284805">"Déplacement des fichiers"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Suppression des fichiers"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Durée restante : <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Copier de <xliff:g id="COUNT_1">%1$d</xliff:g> fichier en cours.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Certains fichiers ont été convertis"</string>
<string name="allow" msgid="7225948811296386551">"Autoriser"</string>
<string name="deny" msgid="2081879885755434506">"Refuser"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier?</item>
+ <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index 84021b0..531a4ee 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Partager via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copie de fichiers en cours"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Déplacement de fichiers"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Suppression des fichiers…"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Temps restant : <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Copie de <xliff:g id="COUNT_1">%1$d</xliff:g> fichier en cours…</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Certains fichiers ont été convertis"</string>
<string name="allow" msgid="7225948811296386551">"Autoriser"</string>
<string name="deny" msgid="2081879885755434506">"Refuser"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier ?</item>
+ <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers ?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml
index fd03af7..3d7bdc2 100644
--- a/packages/DocumentsUI/res/values-gl-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Compartir a través de"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copiando ficheiros"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Mover ficheiros"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Eliminando ficheiros"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Tempo restante: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Convertéronse algúns ficheiros"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
<string name="deny" msgid="2081879885755434506">"Rexeitar"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Queres eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros?</item>
+ <item quantity="one">Queres eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-gu-rIN/strings.xml b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
index 11519a1..4559354 100644
--- a/packages/DocumentsUI/res/values-gu-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
@@ -67,7 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"આના દ્વારા શેર કરો"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ફાઇલો કૉપિ કરી રહ્યાં છે"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ફાઇલો ખસેડી રહ્યાં છે"</string>
- <string name="delete_notification_title" msgid="3329403967712437496">"ફાઇલોને કાઢી નાખી રહ્યાં છે"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"ફાઇલને નીકાળી રહ્યાં છે"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> બાકી"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલો કૉપિ કરી રહ્યાં છે.</item>
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"કેટલીક ફાઇલો રૂપાંતરિત કરી હતી"</string>
<string name="allow" msgid="7225948811296386551">"મંજૂરી આપો"</string>
<string name="deny" msgid="2081879885755434506">"નકારો"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"ફાઇલોને કાઢી નાખીએ?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="one">શું તમે ખરેખર <xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલને કાઢી નાખવા માગો છો?</item>
- <item quantity="other">શું તમે ખરેખર <xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલને કાઢી નાખવા માગો છો?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલ કાઢી નાખીએ?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલ કાઢી નાખીએ?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index dcb7805..b00b5f8 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"कुछ फ़ाइलें रूपांतरित हो गई थीं"</string>
<string name="allow" msgid="7225948811296386551">"अनुमति दें"</string>
<string name="deny" msgid="2081879885755434506">"अस्वीकारें"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"फ़ाइलें हटाएं?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="one">क्या आप वाकई <xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें हटाना चाहते हैं?</item>
- <item quantity="other">क्या आप वाकई <xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें हटाना चाहते हैं?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें हटाएं?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें हटाएं?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index 7d9b6f0..c413e5f 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -119,10 +119,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke su datoteke konvertirane"</string>
<string name="allow" msgid="7225948811296386551">"Dopusti"</string>
<string name="deny" msgid="2081879885755434506">"Odbij"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"Izbrisati datoteke?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="one">Jeste li sigurni da želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku?</item>
- <item quantity="few">Jeste li sigurni da želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
- <item quantity="other">Jeste li sigurni da želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku?</item>
+ <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
+ <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index ac40f87..c3dca3e 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Egyes fájlokat konvertált a rendszer"</string>
<string name="allow" msgid="7225948811296386551">"Engedélyezés"</string>
<string name="deny" msgid="2081879885755434506">"Elutasítás"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"Törli a fájlokat?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other">Biztosan töröl <xliff:g id="COUNT_1">%1$d</xliff:g> fájlt?</item>
- <item quantity="one">Biztosan töröl <xliff:g id="COUNT_0">%1$d</xliff:g> fájlt?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Töröl <xliff:g id="COUNT_1">%1$d</xliff:g> fájlt?</item>
+ <item quantity="one">Töröl <xliff:g id="COUNT_0">%1$d</xliff:g> fájlt?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 2ad2aa7..f811928 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Տարածել"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Ֆայլերի պատճենում"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Ֆայլերի տեղափոխում"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Ֆայլերը ջնջվում են"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Մնացել է <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլի պատճենում:</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Որոշ ֆայլեր փոխարկվել են"</string>
<string name="allow" msgid="7225948811296386551">"Թույլատրել"</string>
<string name="deny" msgid="2081879885755434506">"Մերժել"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ:</item>
+ <item quantity="other">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ:</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index 66d40d2..ecf668c 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Bagikan melalui"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Menyalin file"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Memindahkan file"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Menghapus file"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> lagi"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Menyalin <xliff:g id="COUNT_1">%1$d</xliff:g> file.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Beberapa file dikonversi"</string>
<string name="allow" msgid="7225948811296386551">"Izinkan"</string>
<string name="deny" msgid="2081879885755434506">"Tolak"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Hapus <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
+ <item quantity="one">Hapus <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml
index 290ec92..5606d8f 100644
--- a/packages/DocumentsUI/res/values-is-rIS/strings.xml
+++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Deila í gegnum"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Afritar skrár"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Skrár færðar"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Eyðir skrám"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> eftir"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Afritar <xliff:g id="COUNT_1">%1$d</xliff:g> skrá.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sumum skrám var umbreytt"</string>
<string name="allow" msgid="7225948811296386551">"Leyfa"</string>
<string name="deny" msgid="2081879885755434506">"Hafna"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrá?</item>
+ <item quantity="other">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrám?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index 43f5fcb..959f33a 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Condividi via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copia di file in corso"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Spostamento di file"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Eliminazione dei file"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> rimanenti"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Copia di <xliff:g id="COUNT_1">%1$d</xliff:g> file in corso.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alcuni file sono stati convertiti"</string>
<string name="allow" msgid="7225948811296386551">"Consenti"</string>
<string name="deny" msgid="2081879885755434506">"Nega"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
+ <item quantity="one">Eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index 622785c..3c57e8a 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"שתף באמצעות"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"מעתיק קבצים"</string>
<string name="move_notification_title" msgid="6193835179777284805">"מעביר קבצים"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"מחיקת קבצים מתבצעת"</string>
<string name="copy_remaining" msgid="6283790937387975095">"זמן נותר: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="two">מעתיק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים.</item>
@@ -127,7 +126,10 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"קבצים מסוימים הומרו"</string>
<string name="allow" msgid="7225948811296386551">"אפשר"</string>
<string name="deny" msgid="2081879885755434506">"דחה"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="two">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים?</item>
+ <item quantity="many">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים?</item>
+ <item quantity="other">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים?</item>
+ <item quantity="one">האם למחוק קובץ <xliff:g id="COUNT_0">%1$d</xliff:g>?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index 3319af0..fbfa5ed 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"共有ツール"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ファイルのコピー中"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ファイルを移動中"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"ファイルを削除しています"</string>
<string name="copy_remaining" msgid="6283790937387975095">"残り<xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>個のファイルをコピーしています。</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"一部のファイルが変換されました"</string>
<string name="allow" msgid="7225948811296386551">"許可"</string>
<string name="deny" msgid="2081879885755434506">"拒否"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個のファイルを削除しますか?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個のファイルを削除しますか?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index 30b78e5..ea3633c 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"გაზიარება:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"მიმდ. ფაილების კოპირება"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ფაილების გადაადგილება"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"ფაილების წაშლა…"</string>
<string name="copy_remaining" msgid="6283790937387975095">"დარჩა <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">მიმდინარეობს <xliff:g id="COUNT_1">%1$d</xliff:g> ფაილის კოპირება.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ზოგიერთი ფაილი გარდაქმნილია"</string>
<string name="allow" msgid="7225948811296386551">"უფლების მიცემა"</string>
<string name="deny" msgid="2081879885755434506">"აკრძალვა"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">გსურთ <xliff:g id="COUNT_1">%1$d</xliff:g> ფაილის წაშლა?</item>
+ <item quantity="one">გსურთ <xliff:g id="COUNT_0">%1$d</xliff:g> ფაილის წაშლა?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
index ab045c6..1618e13 100644
--- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
+++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Бөлісу"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Файлдарды көшіру"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Файлдар тасымалдануда"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Файлдар жойылуда"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> қалды"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файлды көшіру.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Кейбір файлдар түрлендірілді"</string>
<string name="allow" msgid="7225948811296386551">"Рұқсат беру"</string>
<string name="deny" msgid="2081879885755434506">"Бас тарту"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файлды жою керек пе?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файлды жою керек пе?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index a084f81..3934348 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ឯកសារមួយចំនួនត្រូវបានបម្លែង"</string>
<string name="allow" msgid="7225948811296386551">"អនុញ្ញាត"</string>
<string name="deny" msgid="2081879885755434506">"បដិសេធ"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"លុបឯកសារឬទេ?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other">តើអ្នកប្រាកដថាអ្នកចង់លុប <xliff:g id="COUNT_1">%1$d</xliff:g> ឯកសារឬទេ?</item>
- <item quantity="one">តើអ្នកប្រាកដថាអ្នកចង់លុប <xliff:g id="COUNT_0">%1$d</xliff:g> ឯកសារឬទេ?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">លុបឯកសារ <xliff:g id="COUNT_1">%1$d</xliff:g> ច្បាប់ឬ?</item>
+ <item quantity="one">លុបឯកសារ <xliff:g id="COUNT_0">%1$d</xliff:g> ច្បាប់ឬ?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
index 55c9697..0dda6f1 100644
--- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ಕೆಲವು ಫೈಲ್ಗಳನ್ನು ಪರಿವರ್ತಿಸಲಾಗಿದೆ"</string>
<string name="allow" msgid="7225948811296386551">"ಅನುಮತಿಸು"</string>
<string name="deny" msgid="2081879885755434506">"ನಿರಾಕರಿಸು"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"ಫೈಲ್ಗಳನ್ನು ಅಳಿಸುವುದೇ?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ಅಳಿಸಲು ನೀವು ಖಚಿತವಾಗಿ ಬಯಸುವಿರಾ?</item>
- <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ಅಳಿಸಲು ನೀವು ಖಚಿತವಾಗಿ ಬಯಸುವಿರಾ?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+ <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index 37642d1..bb6c6530d 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -112,8 +112,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"일부 파일이 변환되었습니다."</string>
<string name="allow" msgid="7225948811296386551">"허용"</string>
<string name="deny" msgid="2081879885755434506">"거부"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"파일을 삭제하시겠습니까?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
<item quantity="other">파일 <xliff:g id="COUNT_1">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
<item quantity="one">파일 <xliff:g id="COUNT_0">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
</plurals>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
index ba3a6e3..ec5faf8 100644
--- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml
+++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Кийинки аркылуу бөлүшүү:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Файлдар көчүрүлүүдө"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Файлдар жылдырылууда…"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Файлдар жок кылынууда"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> калды"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл көчүрүлүүдө.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Айрым файлдардын форматы өзгөртүлдү"</string>
<string name="allow" msgid="7225948811296386551">"Уруксат берүү"</string>
<string name="deny" msgid="2081879885755434506">"Жок"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл жок кылынсынбы?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файл жок кылынсынбы?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index edfca5c..b896835 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ປ່ຽນແປງບາງໄຟລ໌ແລ້ວ"</string>
<string name="allow" msgid="7225948811296386551">"ອະນຸຍາດ"</string>
<string name="deny" msgid="2081879885755434506">"ປະຕິເສດ"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"ລຶບໄຟລ໌ອອກບໍ?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other">ທ່ານແນ່ໃຈບໍ່ວ່າຕ້ອງການລຶບ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟລ໌?</item>
- <item quantity="one">ທ່ານແນ່ໃຈບໍ່ວ່າຕ້ອງການລຶບ <xliff:g id="COUNT_0">%1$d</xliff:g> ໄຟລ໌?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">ລຶບ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟລ໌ອອກບໍ?</item>
+ <item quantity="one">ລຶບ <xliff:g id="COUNT_0">%1$d</xliff:g> ໄຟລ໌ອອກບໍ?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index 7e42922..71fe331 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Bendrinti naudojant"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopijuojami failai"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Perkeliami failai"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Failų ištrynimas"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Liko: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Kopijuojamas <xliff:g id="COUNT_1">%1$d</xliff:g> failas.</item>
@@ -127,7 +126,10 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Kai kurie failai buvo konvertuoti"</string>
<string name="allow" msgid="7225948811296386551">"Leisti"</string>
<string name="deny" msgid="2081879885755434506">"Atmesti"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failą?</item>
+ <item quantity="few">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failus?</item>
+ <item quantity="many">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failo?</item>
+ <item quantity="other">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failų?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 14bd7a8..d974573 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Kopīgot, izmantojot"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Notiek failu kopēšana"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Failu pārvietošana"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Notiek failu dzēšana"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Atlikušais laiks: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="zero">Notiek <xliff:g id="COUNT_1">%1$d</xliff:g> failu kopēšana.</item>
@@ -120,7 +119,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Daži faili tika pārveidoti."</string>
<string name="allow" msgid="7225948811296386551">"Atļaut"</string>
<string name="deny" msgid="2081879885755434506">"Noraidīt"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="zero">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus?</item>
+ <item quantity="one">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failu?</item>
+ <item quantity="other">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
index 129119b..632a510 100644
--- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml
+++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
@@ -67,7 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Сподели преку"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Се копираат датотеки"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Датотеките се преместуваат"</string>
- <string name="delete_notification_title" msgid="3329403967712437496">"Се бришат датотеки"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"Се бришат датотеките"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Уште <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Се копира <xliff:g id="COUNT_1">%1$d</xliff:g> датотека.</item>
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Некои датотеки беа конвертирани"</string>
<string name="allow" msgid="7225948811296386551">"Дозволи"</string>
<string name="deny" msgid="2081879885755434506">"Одбиј"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"Избриши датотеки?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="one">Дали сте сигурни дека сакате да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотека?</item>
- <item quantity="other">Дали сте сигурни дека сакате да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотеки?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Да се избрише <xliff:g id="COUNT_1">%1$d</xliff:g> датотека?</item>
+ <item quantity="other">Да се избрише <xliff:g id="COUNT_1">%1$d</xliff:g> датотеки?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
index 966ddbb..5441e0c 100644
--- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ചില ഫയലുകൾ പരിവർത്തനം ചെയ്യപ്പെട്ടു"</string>
<string name="allow" msgid="7225948811296386551">"അനുവദിക്കുക"</string>
<string name="deny" msgid="2081879885755434506">"നിരസിക്കുക"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"ഫയലുകൾ ഇല്ലാതാക്കണോ?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഫയലുകൾ ഇല്ലാതാക്കണമെന്ന് നിങ്ങൾക്ക് തീർച്ചയാണോ?</item>
- <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ഫയൽ ഇല്ലാതാക്കണമെന്ന് നിങ്ങൾക്ക് തീർച്ചയാണോ?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഫയലുകൾ ഇല്ലാതാക്കണോ?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ഫയൽ ഇല്ലാതാക്കണോ?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index 8531295..b556188 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Дараахаар дамжуулан хуваалцах"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Файлуудыг хуулж байна"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Файлыг зөөвөрлөж байна"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Эдгээр файлыг устгаж байна"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> үлдсэн"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> файлуудыг хуулж байна.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Зарим файлыг хөрвүүлсэн"</string>
<string name="allow" msgid="7225948811296386551">"Зөвшөөрөх"</string>
<string name="deny" msgid="2081879885755434506">"Татгалзах"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> файлыг устгах уу?</item>
+ <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> файлыг устгах уу?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/strings.xml b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
index f747d1a..721f2d2 100644
--- a/packages/DocumentsUI/res/values-mr-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"द्वारे सामायिक करा"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"फायली कॉपी करीत आहे"</string>
<string name="move_notification_title" msgid="6193835179777284805">"फायली हलविणे"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"फायली हटवित आहे"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> शिल्लक"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फाईल कॉपी करीत आहे.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"काही फायली रूपांतरित केल्या होत्या"</string>
<string name="allow" msgid="7225948811296386551">"अनुमती द्या"</string>
<string name="deny" msgid="2081879885755434506">"नकार द्या"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> फाईल हटवायची?</item>
+ <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> फायली हटवायच्या?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index d481125..9985eb6 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Kongsi melalui"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Menyalin fail"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Mengalihkan fail"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Memadamkan fail"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> lagi"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Menyalin <xliff:g id="COUNT_1">%1$d</xliff:g> fail.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sesetengah fail telah ditukarkan"</string>
<string name="allow" msgid="7225948811296386551">"Benarkan"</string>
<string name="deny" msgid="2081879885755434506">"Nafi"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Padamkan <xliff:g id="COUNT_1">%1$d</xliff:g> fail?</item>
+ <item quantity="one">Padamkan <xliff:g id="COUNT_0">%1$d</xliff:g> fail?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml
index 13392fc..3e581ae 100644
--- a/packages/DocumentsUI/res/values-my-rMM/strings.xml
+++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"အချို့ဖိုင်များကို ပြောင်းလဲထားသည်"</string>
<string name="allow" msgid="7225948811296386551">"ခွင့်ပြုသည်"</string>
<string name="deny" msgid="2081879885755434506">"ငြင်းပယ်သည်"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"ဖိုင်များကို ဖျက်မလား။"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ဖိုင်များကိုဖျက်ရန် သေချာပါသလား။</item>
- <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ဖိုင်ကိုဖျက်ရန် သေချာပါသလား။</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">ဖိုင် <xliff:g id="COUNT_1">%1$d</xliff:g> ခုကိုဖျက်မလား။</item>
+ <item quantity="one">ဖိုင် <xliff:g id="COUNT_0">%1$d</xliff:g> ခုကိုဖျက်မလား။</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index 8271428..8257d4a 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Del via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopierer filer"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Flytter filer"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Sletter filene"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> gjenstår"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Kopierer <xliff:g id="COUNT_1">%1$d</xliff:g> filer.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Noen filer er konvertert"</string>
<string name="allow" msgid="7225948811296386551">"Tillat"</string>
<string name="deny" msgid="2081879885755434506">"Avslå"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
+ <item quantity="one">Vil du slette <xliff:g id="COUNT_0">%1$d</xliff:g> fil?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
index d0bc737..2320192 100644
--- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml
+++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"केही फाइलहरू परिवर्तन गरिएका थिए"</string>
<string name="allow" msgid="7225948811296386551">"अनुमति दिनुहोस्"</string>
<string name="deny" msgid="2081879885755434506">"अस्वीकार गर्नुहोस्"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"फाइलहरूलाई मेट्ने हो?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other">तपाईँ निश्चित रूपमा <xliff:g id="COUNT_1">%1$d</xliff:g> फाइलहरूलाई मेट्न चाहनुहुन्छ?</item>
- <item quantity="one">तपाईँ निश्चित रूपमा <xliff:g id="COUNT_0">%1$d</xliff:g> फाइललाई मेट्न चाहनुहुन्छ?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फाइलहरूलाई मेट्ने हो?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> फाइललाई मेट्ने हो?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 257e7e4..17b6031 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sommige bestanden zijn geconverteerd"</string>
<string name="allow" msgid="7225948811296386551">"Toestaan"</string>
<string name="deny" msgid="2081879885755434506">"Weigeren"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"Bestanden verwijderen?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other">Weet je zeker dat je <xliff:g id="COUNT_1">%1$d</xliff:g> bestanden wilt verwijderen?</item>
- <item quantity="one">Weet je zeker dat je <xliff:g id="COUNT_0">%1$d</xliff:g> bestand wilt verwijderen?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> bestanden verwijderen?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> bestand verwijderen?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-pa-rIN/strings.xml b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
index 7dca3cf..009acbea 100644
--- a/packages/DocumentsUI/res/values-pa-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ਕੁਝ ਫ਼ਾਈਲਾਂ ਤਬਦੀਲ ਕੀਤੀਆਂ ਗਈਆਂ ਸਨ"</string>
<string name="allow" msgid="7225948811296386551">"ਆਗਿਆ ਦਿਓ"</string>
<string name="deny" msgid="2081879885755434506">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"ਕੀ ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="one">ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ \'ਤੇ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?</item>
- <item quantity="other">ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ \'ਤੇ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+ <item quantity="other">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 7330e1e..b9bec5d 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Udostępnij przez:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopiowanie plików"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Przenoszenie plików"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Usuwam pliki"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Pozostało: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="few">Kopiowanie <xliff:g id="COUNT_1">%1$d</xliff:g> plików.</item>
@@ -127,7 +126,10 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Niektóre pliki zostały przekonwertowane"</string>
<string name="allow" msgid="7225948811296386551">"Zezwól"</string>
<string name="deny" msgid="2081879885755434506">"Odmów"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="few">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> pliki?</item>
+ <item quantity="many">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> plików?</item>
+ <item quantity="other">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> pliku?</item>
+ <item quantity="one">Usunąć <xliff:g id="COUNT_0">%1$d</xliff:g> plik?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-pt-rBR/strings.xml b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
index 44f2ab8..158bd1d 100644
--- a/packages/DocumentsUI/res/values-pt-rBR/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Compartilhar via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copiando arquivos"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Movendo arquivos"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Excluindo arquivos"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> restantes"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns arquivos foram convertidos"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
<string name="deny" msgid="2081879885755434506">"Negar"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+ <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index 3d999c7..14c6291 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Partilhar através de"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"A copiar ficheiros"</string>
<string name="move_notification_title" msgid="6193835179777284805">"A mover ficheiros"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Eliminar ficheiros"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Faltam <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">A copiar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns ficheiros foram convertidos"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
<string name="deny" msgid="2081879885755434506">"Recusar"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Pretende eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros?</item>
+ <item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index 44f2ab8..158bd1d 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Compartilhar via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copiando arquivos"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Movendo arquivos"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Excluindo arquivos"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> restantes"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns arquivos foram convertidos"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
<string name="deny" msgid="2081879885755434506">"Negar"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+ <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index d256a26..241be4e 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Trimiteți prin"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Se copiază fișierele"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Se mută fișierele"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Se șterg fișierele"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Timp rămas: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="few">Se copiază <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere.</item>
@@ -120,7 +119,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Unele fișiere au fost convertite"</string>
<string name="allow" msgid="7225948811296386551">"Permiteți"</string>
<string name="deny" msgid="2081879885755434506">"Refuzați"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="few">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere?</item>
+ <item quantity="other">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> de fișiere?</item>
+ <item quantity="one">Ștergeți <xliff:g id="COUNT_0">%1$d</xliff:g> fișier?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index 161bb19..606c1c5 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Поделиться"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Копирование файлов"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Перемещение файлов"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Удаление файлов…"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Осталось <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Копируется <xliff:g id="COUNT_1">%1$d</xliff:g> файл...</item>
@@ -127,7 +126,10 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Формат некоторых файлов изменен"</string>
<string name="allow" msgid="7225948811296386551">"Разрешить"</string>
<string name="deny" msgid="2081879885755434506">"Отклонить"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файл?</item>
+ <item quantity="few">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+ <item quantity="many">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файлов?</item>
+ <item quantity="other">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml
index ae85f32..a818bae 100644
--- a/packages/DocumentsUI/res/values-si-rLK/strings.xml
+++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"සමහර ගොනු පරිවර්තනය කරන ලදී"</string>
<string name="allow" msgid="7225948811296386551">"අවසර දෙන්න"</string>
<string name="deny" msgid="2081879885755434506">"ප්රතික්ෂේප කරන්න"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"ගොනු මකන්නද?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="one">ඔබට ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g>ක් මැකීමට අවශ්ය බව විශ්වාසද?</item>
- <item quantity="other">ඔබට ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g>ක් මැකීමට අවශ්ය බව විශ්වාසද?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g>ක් මකන්නද?</item>
+ <item quantity="other">ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g>ක් මකන්නද?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index 7919533..d8b1970 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Zdieľať"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopírovanie súborov"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Presúvajú sa súbory"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Odstraňujú sa súbory"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Zostáva: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="few">Kopírujú sa <xliff:g id="COUNT_1">%1$d</xliff:g> súbory.</item>
@@ -127,7 +126,10 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Niektoré súbory boli konvertované"</string>
<string name="allow" msgid="7225948811296386551">"Povoliť"</string>
<string name="deny" msgid="2081879885755434506">"Zamietnuť"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="few">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súbory?</item>
+ <item quantity="many">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súboru?</item>
+ <item quantity="other">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súborov?</item>
+ <item quantity="one">Odstrániť <xliff:g id="COUNT_0">%1$d</xliff:g> súbor?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index afcdb6a..c7ab185 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -126,11 +126,10 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Nekatere datoteke so bile pretvorjene"</string>
<string name="allow" msgid="7225948811296386551">"Dovoli"</string>
<string name="deny" msgid="2081879885755434506">"Zavrni"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"Ali želite izbrisati datoteke?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="one">Ali res želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteko?</item>
- <item quantity="two">Ali res želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteki?</item>
- <item quantity="few">Ali res želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
- <item quantity="other">Ali res želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datotek?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteko?</item>
+ <item quantity="two">Želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteki?</item>
+ <item quantity="few">Želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
+ <item quantity="other">Želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datotek?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sq-rAL/strings.xml b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
index 7934b16..be87dc2 100644
--- a/packages/DocumentsUI/res/values-sq-rAL/strings.xml
+++ b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Disa skedarë u konvertuan"</string>
<string name="allow" msgid="7225948811296386551">"Lejo"</string>
<string name="deny" msgid="2081879885755434506">"Moho"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"Të fshihen skedarët?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other">Je i sigurt se dëshiron të fshish <xliff:g id="COUNT_1">%1$d</xliff:g> skedarë?</item>
- <item quantity="one">Je i sigurt se dëshiron të fshish <xliff:g id="COUNT_0">%1$d</xliff:g> skedar?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Të fshihen <xliff:g id="COUNT_1">%1$d</xliff:g> skedarë?</item>
+ <item quantity="one">Të fshihet <xliff:g id="COUNT_0">%1$d</xliff:g> skedar?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index ffa6944..ae6b11b 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Делите преко"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Копирање датотека"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Датотеке се премештају"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Датотеке се бришу"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Још <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Копирање <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке.</item>
@@ -120,7 +119,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Неке датотеке су конвертоване"</string>
<string name="allow" msgid="7225948811296386551">"Дозволи"</string>
<string name="deny" msgid="2081879885755434506">"Одбиј"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотеку?</item>
+ <item quantity="few">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке?</item>
+ <item quantity="other">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотека?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index 656ef8f..1e7eb60 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Dela via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopierar filer"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Filer flyttas"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Filerna tas bort"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> återstår"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Kopierar <xliff:g id="COUNT_1">%1$d</xliff:g> filer.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Vissa filer konverterades"</string>
<string name="allow" msgid="7225948811296386551">"Tillåt"</string>
<string name="deny" msgid="2081879885755434506">"Neka"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Radera <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
+ <item quantity="one">Radera <xliff:g id="COUNT_0">%1$d</xliff:g> fil?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index c50920b..b3f0a6d 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Baadhi ya faili zimebadilishwa muundo"</string>
<string name="allow" msgid="7225948811296386551">"Ruhusu"</string>
<string name="deny" msgid="2081879885755434506">"Kataza"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"Ungependa kufuta faili?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other">Una uhakika kuwa ungependa kufuta faili <xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
- <item quantity="one">Una uhakika kuwa ungependa kufuta faili <xliff:g id="COUNT_0">%1$d</xliff:g>?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Ungependa kufuta faili <xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+ <item quantity="one">Ungependa kufuta faili <xliff:g id="COUNT_0">%1$d</xliff:g>?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/dimens.xml b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
index 2488fa2..b5d1150 100644
--- a/packages/DocumentsUI/res/values-sw720dp/dimens.xml
+++ b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
@@ -18,4 +18,6 @@
<dimen name="grid_padding_horiz">16dp</dimen>
<dimen name="grid_padding_vert">16dp</dimen>
+ <dimen name="list_item_padding">24dp</dimen>
+
</resources>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
index 08dc5ba..7c19e53 100644
--- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"சில கோப்புகள் மாற்றப்பட்டன"</string>
<string name="allow" msgid="7225948811296386551">"அனுமதி"</string>
<string name="deny" msgid="2081879885755434506">"நிராகரி"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"கோப்புகளை நீக்கவா?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகளை நிச்சயமாக நீக்கவா?</item>
- <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்பை நிச்சயமாக நீக்கவா?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகளை நீக்கவா?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்பை நீக்கவா?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-te-rIN/strings.xml b/packages/DocumentsUI/res/values-te-rIN/strings.xml
index ad8c840..d12bbb8 100644
--- a/packages/DocumentsUI/res/values-te-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-te-rIN/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"కొన్ని పైల్లు మార్చబడ్డాయి"</string>
<string name="allow" msgid="7225948811296386551">"అనుమతించండి"</string>
<string name="deny" msgid="2081879885755434506">"తిరస్కరించండి"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"ఫైల్లను తొలగించాలా?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other">మీరు ఖచ్చితంగా <xliff:g id="COUNT_1">%1$d</xliff:g> ఫైల్లను తొలగించాలనుకుంటున్నారా?</item>
- <item quantity="one">మీరు ఖచ్చితంగా <xliff:g id="COUNT_0">%1$d</xliff:g> ఫైల్ను తొలగించాలనుకుంటున్నారా?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఫైల్లను తొలగించాలా?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఫైల్ను తొలగించాలా?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index ad4c5b9..678628c 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"แชร์ผ่าน"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"กำลังคัดลอกไฟล์"</string>
<string name="move_notification_title" msgid="6193835179777284805">"กำลังย้ายไฟล์"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"กำลังลบไฟล์"</string>
<string name="copy_remaining" msgid="6283790937387975095">"เหลือ <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">กำลังคัดลอก <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"แปลงบางไฟล์แล้ว"</string>
<string name="allow" msgid="7225948811296386551">"อนุญาต"</string>
<string name="deny" msgid="2081879885755434506">"ปฏิเสธ"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">ลบ <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์ใช่ไหม</item>
+ <item quantity="one">ลบ <xliff:g id="COUNT_0">%1$d</xliff:g> ไฟล์ใช่ไหม</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index 8c8b018..9079c55 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Ibahagi sa pamamagitan ng"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kinokopya ang mga file"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Inililipat ang mga file"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Pagde-delete ng mga file"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> na lang ang natitira"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Kumokopya ng <xliff:g id="COUNT_1">%1$d</xliff:g> file.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Na-convert ang ilang file"</string>
<string name="allow" msgid="7225948811296386551">"Payagan"</string>
<string name="deny" msgid="2081879885755434506">"Tanggihan"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
+ <item quantity="other">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> na file?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 602f8d7..a462491 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Şunu kullanarak paylaş:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Dosyalar kopyalanıyor"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Dosyalar taşınıyor"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Dosyalar siliniyor"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> kaldı"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya kopyalanıyor.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bazı dosyalar dönüştürüldü"</string>
<string name="allow" msgid="7225948811296386551">"İzin Ver"</string>
<string name="deny" msgid="2081879885755434506">"Reddet"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya silinsin mi?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosya silinsin mi?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index 15ae424..2fc411e 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Надіслати через"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Копіювання файлів"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Переміщення файлів"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Видалення файлів"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Залишилося <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Копіювання <xliff:g id="COUNT_1">%1$d</xliff:g> файлу.</item>
@@ -127,7 +126,10 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Деякі файли конвертовано"</string>
<string name="allow" msgid="7225948811296386551">"Дозвол."</string>
<string name="deny" msgid="2081879885755434506">"Забор."</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файл?</item>
+ <item quantity="few">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файли?</item>
+ <item quantity="many">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файлів?</item>
+ <item quantity="other">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файлу?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
index 272677f..733d312 100644
--- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml
+++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"اشتراک کریں بذریعہ"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"فائلیں کاپی ہو رہی ہیں"</string>
<string name="move_notification_title" msgid="6193835179777284805">"فائلیں منتقل ہو رہی ہیں"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"فائلیں حذف کی جا رہی ہیں"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> باقی ہے"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں کاپی کی جا رہی ہیں۔</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"کچھ فائلوں کو تبدیل کیا گیا تھا"</string>
<string name="allow" msgid="7225948811296386551">"اجازت دیں"</string>
<string name="deny" msgid="2081879885755434506">"مسترد کریں"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں حذف کریں؟</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> فائل حذف کریں؟</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index 0a599c5..20da8d0 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Quyidagi orqali ulashish"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Fayllar nusxalanmoqda"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Ko‘chirib o‘tkazilmoqda"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Fayllar o‘chirilmoqda"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> qoldi"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ta fayl nusxalanmoqda</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bir nechta fayllar o‘girildi"</string>
<string name="allow" msgid="7225948811296386551">"Ruxsat berish"</string>
<string name="deny" msgid="2081879885755434506">"Rad qilish"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta fayl o‘chirilsinmi?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta fayl o‘chirilsinmi?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index 0abb389..c7df892 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -112,9 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Đã chuyển đổi một số tệp"</string>
<string name="allow" msgid="7225948811296386551">"Cho phép"</string>
<string name="deny" msgid="2081879885755434506">"Từ chối"</string>
- <string name="delete_confirmation_title" msgid="1958369150786342998">"Xóa tệp?"</string>
- <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
- <item quantity="other">Bạn có chắc chắn muốn xóa <xliff:g id="COUNT_1">%1$d</xliff:g> tệp không?</item>
- <item quantity="one">Bạn có chắc chắn muốn xóa <xliff:g id="COUNT_0">%1$d</xliff:g> tệp không?</item>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">Xóa <xliff:g id="COUNT_1">%1$d</xliff:g> tệp?</item>
+ <item quantity="one">Xóa <xliff:g id="COUNT_0">%1$d</xliff:g> tệp?</item>
</plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index 83a9204..15deb7b 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"分享方式"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"正在复制文件"</string>
<string name="move_notification_title" msgid="6193835179777284805">"正在移动文件"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"正在删除文件"</string>
<string name="copy_remaining" msgid="6283790937387975095">"剩余时间:<xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">正在复制 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件。</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分文件已转换成其他格式"</string>
<string name="allow" msgid="7225948811296386551">"允许"</string>
<string name="deny" msgid="2081879885755434506">"拒绝"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">要删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件吗?</item>
+ <item quantity="one">要删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件吗?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index 532f976..dd95df5 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"分享方式:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"正在複製檔案"</string>
<string name="move_notification_title" msgid="6193835179777284805">"正在移動檔案"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"正在刪除檔案"</string>
<string name="copy_remaining" msgid="6283790937387975095">"剩餘 <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">正在複製 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案。</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分檔案已轉換成其他格式"</string>
<string name="allow" msgid="7225948811296386551">"允許"</string>
<string name="deny" msgid="2081879885755434506">"拒絕"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案嗎?</item>
+ <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個檔案嗎?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index e8b48cc..41ed922 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"分享方式:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"複製檔案"</string>
<string name="move_notification_title" msgid="6193835179777284805">"正在移動檔案"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"正在刪除檔案"</string>
<string name="copy_remaining" msgid="6283790937387975095">"剩餘 <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">正在複製 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案。</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分檔案已轉換成其他格式"</string>
<string name="allow" msgid="7225948811296386551">"允許"</string>
<string name="deny" msgid="2081879885755434506">"拒絕"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案嗎?</item>
+ <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個檔案嗎?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index b22f994..cc90163 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -67,8 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Yabelana nge-"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Ikopisha amafayela"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Ihambisa amafayela"</string>
- <!-- no translation found for delete_notification_title (3329403967712437496) -->
- <skip />
+ <string name="delete_notification_title" msgid="3329403967712437496">"Ukususa amafayela"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> okusele"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Ikopisha amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>.</item>
@@ -113,7 +112,8 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Amanye amafayela aguqulelwe"</string>
<string name="allow" msgid="7225948811296386551">"Vumela"</string>
<string name="deny" msgid="2081879885755434506">"Yala"</string>
- <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
- <skip />
- <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+ <plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
+ <item quantity="one">Sula amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+ <item quantity="other">Sula amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+ </plurals>
</resources>
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/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 46cbbdf..6efe9d1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -39,6 +39,7 @@
import android.support.annotation.CallSuper;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
@@ -67,6 +68,7 @@
SearchViewManager mSearchManager;
DrawerController mDrawer;
NavigationView mNavigator;
+ List<EventListener> mEventListeners = new ArrayList<>();
private final String mTag;
@@ -149,7 +151,6 @@
final MenuItem sortSize = menu.findItem(R.id.menu_sort_size);
final MenuItem grid = menu.findItem(R.id.menu_grid);
final MenuItem list = menu.findItem(R.id.menu_list);
- final MenuItem advanced = menu.findItem(R.id.menu_advanced);
final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
// Search uses backend ranking; no sorting, recents doesn't support sort.
@@ -161,9 +162,6 @@
grid.setVisible(mState.derivedMode != State.MODE_GRID);
list.setVisible(mState.derivedMode != State.MODE_LIST);
- advanced.setVisible(!mState.forceAdvanced);
- advanced.setTitle(LocalPreferences.getDisplayAdvancedDevices(this)
- ? R.string.menu_advanced_hide : R.string.menu_advanced_show);
fileSize.setTitle(LocalPreferences.getDisplayFileSize(this)
? R.string.menu_file_size_hide : R.string.menu_file_size_show);
@@ -199,10 +197,6 @@
state.forceSize = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, false);
state.showSize = state.forceSize || LocalPreferences.getDisplayFileSize(this);
- state.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
- state.showAdvanced = state.forceAdvanced
- || LocalPreferences.getDisplayAdvancedDevices(this);
-
state.initAcceptMimes(intent);
state.excludedAuthorities = getExcludedAuthorities();
@@ -278,10 +272,6 @@
}
return true;
- case R.id.menu_advanced:
- setDisplayAdvancedDevices(!LocalPreferences.getDisplayAdvancedDevices(this));
- return true;
-
case R.id.menu_file_size:
setDisplayFileSize(!LocalPreferences.getDisplayFileSize(this));
return true;
@@ -329,6 +319,8 @@
void openContainerDocument(DocumentInfo doc) {
assert(doc.isContainer());
+ notifyDirectoryNavigated(doc.derivedUri);
+
mState.pushDocument(doc);
// Show an opening animation only if pressing "back" would get us back to the
// previous directory. Especially after opening a root document, pressing
@@ -431,13 +423,6 @@
return mState;
}
- void setDisplayAdvancedDevices(boolean display) {
- LocalPreferences.setDisplayAdvancedDevices(this, display);
- mState.showAdvanced = mState.forceAdvanced | display;
- RootsFragment.get(getFragmentManager()).onDisplayStateChanged();
- invalidateOptionsMenu();
- }
-
void setDisplayFileSize(boolean display) {
LocalPreferences.setDisplayFileSize(this, display);
mState.showSize = display;
@@ -594,6 +579,28 @@
return super.onKeyDown(keyCode, event);
}
+ @VisibleForTesting
+ public void addEventListener(EventListener listener) {
+ mEventListeners.add(listener);
+ }
+
+ @VisibleForTesting
+ public void removeEventListener(EventListener listener) {
+ mEventListeners.remove(listener);
+ }
+
+ public void notifyDirectoryLoaded(Uri uri) {
+ for (EventListener listener : mEventListeners) {
+ listener.onDirectoryLoaded(uri);
+ }
+ }
+
+ void notifyDirectoryNavigated(Uri uri) {
+ for (EventListener listener : mEventListeners) {
+ listener.onDirectoryNavigated(uri);
+ }
+ }
+
/**
* Toggles focus between the navigation drawer and the directory listing. If the drawer isn't
* locked, open/close it as appropriate.
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/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 13b7b14..d2e918c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -59,7 +59,6 @@
private CancellationSignal mSignal;
private DirectoryResult mResult;
-
public DirectoryLoader(Context context, int type, RootInfo root, DocumentInfo doc, Uri uri,
int userSortOrder, boolean inSearchMode) {
super(context, ProviderExecutor.forAuthority(root.authority));
@@ -84,6 +83,7 @@
final String authority = mUri.getAuthority();
final DirectoryResult result = new DirectoryResult();
+ result.doc = mDoc;
// Use default document when searching
if (mSearchMode) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java
index 22e438a..6268643 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java
@@ -22,12 +22,15 @@
import android.content.ContentProviderClient;
import android.database.Cursor;
+import com.android.documentsui.model.DocumentInfo;
+
import libcore.io.IoUtils;
public class DirectoryResult implements AutoCloseable {
ContentProviderClient client;
public Cursor cursor;
public Exception exception;
+ public DocumentInfo doc;
public int sortOrder = SORT_ORDER_UNKNOWN;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
index b5d3ea0..2f784cb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
@@ -98,12 +98,10 @@
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- final MenuItem advanced = menu.findItem(R.id.menu_advanced);
final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard);
final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
- advanced.setVisible(false);
createDir.setVisible(false);
pasteFromCb.setEnabled(false);
fileSize.setVisible(false);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/EventListener.java b/packages/DocumentsUI/src/com/android/documentsui/EventListener.java
new file mode 100644
index 0000000..c15e9a6
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/EventListener.java
@@ -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.
+ */
+
+package com.android.documentsui;
+
+import android.net.Uri;
+import android.support.annotation.Nullable;
+
+public interface EventListener {
+ /**
+ * @param uri Uri navigated to. If recents, then null.
+ */
+ void onDirectoryNavigated(@Nullable Uri uri);
+
+ /**
+ * @param uri Uri of the loaded directory. If recents, then null.
+ */
+ void onDirectoryLoaded(@Nullable Uri uri);
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index c17be06..c56a12f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -282,6 +282,24 @@
* Launches an intent to view the specified document.
*/
private void openDocument(DocumentInfo doc, Model model) {
+
+ // Provide specialized handling of downloaded APKs This sends the APK
+ // details off to get extra security information added, and finally
+ // to be handled by the package manager.
+ if (MimePredicate.isApkType(doc.mimeType)) {
+ // First try managing the document; we expect manager to filter
+ // based on authority, so we don't grant.
+ final Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT);
+ manage.setData(doc.derivedUri);
+
+ try {
+ startActivity(manage);
+ return;
+ } catch (ActivityNotFoundException ex) {
+ // fall back to regular handling below.
+ }
+ }
+
Intent intent = new QuickViewIntentBuilder(
getPackageManager(), getResources(), doc, model).build();
@@ -296,7 +314,7 @@
}
}
- // Fallback to traditional VIEW action...
+ // Fall back to traditional VIEW action...
intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setData(doc.derivedUri);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
index 170fb89..c7c61c3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
@@ -25,17 +25,9 @@
import com.android.documentsui.model.RootInfo;
public class LocalPreferences {
- private static final String KEY_ADVANCED_DEVICES = "advancedDevices";
private static final String KEY_FILE_SIZE = "fileSize";
private static final String ROOT_VIEW_MODE_PREFIX = "rootViewMode-";
- public static boolean getDisplayAdvancedDevices(Context context) {
- boolean defaultAdvanced = context.getResources()
- .getBoolean(R.bool.config_defaultAdvancedDevices);
- return PreferenceManager.getDefaultSharedPreferences(context)
- .getBoolean(KEY_ADVANCED_DEVICES, defaultAdvanced);
- }
-
public static boolean getDisplayFileSize(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(KEY_FILE_SIZE, false);
@@ -47,11 +39,6 @@
.getInt(createKey(root), fallback);
}
- public static void setDisplayAdvancedDevices(Context context, boolean display) {
- PreferenceManager.getDefaultSharedPreferences(context).edit()
- .putBoolean(KEY_ADVANCED_DEVICES, display).apply();
- }
-
public static void setDisplayFileSize(Context context, boolean display) {
PreferenceManager.getDefaultSharedPreferences(context).edit()
.putBoolean(KEY_FILE_SIZE, display).apply();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
index 9df55a0..2f202e7 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
@@ -16,12 +16,15 @@
package com.android.documentsui;
+import android.annotation.Nullable;
+
import com.android.documentsui.model.DocumentInfo;
import com.android.internal.util.Predicate;
public class MimePredicate implements Predicate<DocumentInfo> {
private final String[] mFilters;
+ private static final String APK_TYPE = "application/vnd.android.package-archive";
/**
* MIME types that are visual in nature. For example, they should always be
* shown as thumbnails in list mode.
@@ -92,4 +95,8 @@
return false;
}
}
+
+ public static boolean isApkType(@Nullable String mimeType) {
+ return APK_TYPE.equals(mimeType);
+ }
}
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/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 6856129c..2b7294a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -17,7 +17,6 @@
package com.android.documentsui;
import static com.android.documentsui.Shared.DEBUG;
-import static com.android.documentsui.Shared.TAG;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
@@ -62,6 +61,8 @@
public static final Uri sNotificationUri = Uri.parse(
"content://com.android.documentsui.roots/");
+ private static final String TAG = "RootsCache";
+
private final Context mContext;
private final ContentObserver mObserver;
private OnCacheUpdateListener mCacheUpdateListener;
@@ -417,45 +418,64 @@
static List<RootInfo> getMatchingRoots(Collection<RootInfo> roots, State state) {
final List<RootInfo> matching = new ArrayList<>();
for (RootInfo root : roots) {
- // Exclude read-only devices when creating
- if (state.action == State.ACTION_CREATE && !root.supportsCreate()) continue;
- if (state.action == State.ACTION_PICK_COPY_DESTINATION
- && !root.supportsCreate()) continue;
- // Exclude roots that don't support directory picking
- if (state.action == State.ACTION_OPEN_TREE && !root.supportsChildren()) continue;
- // Exclude advanced devices when not requested
- if (!state.showAdvanced && root.isAdvanced()) continue;
- // Exclude non-local devices when local only
- if (state.localOnly && !root.isLocalOnly()) continue;
- // Exclude downloads roots as it doesn't support directory creation (actually
- // we just don't show them).
- // TODO: Add flag to check the root supports directory creation.
- if (state.directoryCopy && !root.isDownloads()) continue;
- // Only show empty roots when creating, or in browse mode.
- if (root.isEmpty() && (state.action == State.ACTION_OPEN
- || state.action == State.ACTION_GET_CONTENT)) {
- if (DEBUG) Log.i(TAG, "Skipping empty root: " + root);
+ if (DEBUG) Log.d(TAG, "Evaluating " + root);
+
+ if (state.action == State.ACTION_CREATE && !root.supportsCreate()) {
+ if (DEBUG) Log.d(TAG, "Excluding read-only root because: ACTION_CREATE.");
continue;
}
- // Only include roots that serve requested content
+ if (state.action == State.ACTION_PICK_COPY_DESTINATION
+ && !root.supportsCreate()) {
+ if (DEBUG) Log.d(
+ TAG, "Excluding read-only root because: ACTION_PICK_COPY_DESTINATION.");
+ continue;
+ }
+
+ if (state.action == State.ACTION_OPEN_TREE && !root.supportsChildren()) {
+ if (DEBUG) Log.d(
+ TAG, "Excluding root !supportsChildren because: ACTION_OPEN_TREE.");
+ continue;
+ }
+
+ if (state.localOnly && !root.isLocalOnly()) {
+ if (DEBUG) Log.d(TAG, "Excluding root because: unwanted non-local device.");
+ continue;
+ }
+
+ if (state.directoryCopy && root.isDownloads()) {
+ if (DEBUG) Log.d(
+ TAG, "Excluding downloads root because: unsupported directory copy.");
+ continue;
+ }
+
+ if (state.action == State.ACTION_OPEN && root.isEmpty()) {
+ if (DEBUG) Log.d(TAG, "Excluding empty root because: ACTION_OPEN.");
+ continue;
+ }
+
+ if (state.action == State.ACTION_GET_CONTENT && root.isEmpty()) {
+ if (DEBUG) Log.d(TAG, "Excluding empty root because: ACTION_GET_CONTENT.");
+ continue;
+ }
+
final boolean overlap =
MimePredicate.mimeMatches(root.derivedMimeTypes, state.acceptMimes) ||
MimePredicate.mimeMatches(state.acceptMimes, root.derivedMimeTypes);
if (!overlap) {
- continue;
- }
-
- // Exclude roots from the calling package.
- if (state.excludedAuthorities.contains(root.authority)) {
if (DEBUG) Log.d(
- TAG, "Excluding root " + root.authority + " from calling package.");
+ TAG, "Excluding root because: unsupported content types > "
+ + state.acceptMimes);
continue;
}
- if (DEBUG) Log.d(
- TAG, "Including root " + root + " in roots list.");
+ if (state.excludedAuthorities.contains(root.authority)) {
+ if (DEBUG) Log.d(TAG, "Excluding root because: owned by calling package.");
+ continue;
+ }
+
+ if (DEBUG) Log.d(TAG, "Including " + root);
matching.add(root);
}
return matching;
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/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index 62f9ea7..4f460b4 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -82,8 +82,6 @@
public boolean forceSize;
public boolean showSize;
public boolean localOnly;
- public boolean forceAdvanced;
- public boolean showAdvanced;
public boolean restored;
// Indicates that a copy operation (or move) includes a directory.
@@ -181,8 +179,6 @@
out.writeInt(forceSize ? 1 : 0);
out.writeInt(showSize ? 1 : 0);
out.writeInt(localOnly ? 1 : 0);
- out.writeInt(forceAdvanced ? 1 : 0);
- out.writeInt(showAdvanced ? 1 : 0);
out.writeInt(restored ? 1 : 0);
DurableUtils.writeToParcel(out, stack);
out.writeMap(dirState);
@@ -211,8 +207,6 @@
state.forceSize = in.readInt() != 0;
state.showSize = in.readInt() != 0;
state.localOnly = in.readInt() != 0;
- state.forceAdvanced = in.readInt() != 0;
- state.showAdvanced = in.readInt() != 0;
state.restored = in.readInt() != 0;
DurableUtils.readFromParcel(in, state.stack);
in.readMap(state.dirState, loader);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index dfceff8..1967923 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -17,7 +17,6 @@
package com.android.documentsui.dirlist;
import static com.android.documentsui.Shared.DEBUG;
-import static com.android.documentsui.State.ACTION_MANAGE;
import static com.android.documentsui.State.MODE_GRID;
import static com.android.documentsui.State.MODE_LIST;
import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
@@ -168,6 +167,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 +182,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 +707,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() {
@@ -1290,6 +1303,11 @@
showDirectory();
mAdapter.notifyDataSetChanged();
}
+
+ if (!model.isLoading()) {
+ ((BaseActivity) getActivity()).notifyDirectoryLoaded(
+ model.doc != null ? model.doc.derivedUri : null);
+ }
}
@Override
@@ -1516,7 +1534,7 @@
mRoot.authority, mRoot.rootId, mQuery)
: DocumentsContract.buildChildDocumentsUri(
mDocument.authority, mDocument.documentId);
- if (state.action == ACTION_MANAGE) {
+ if (mTuner.enableManagedMode()) {
contentsUri = DocumentsContract.setManageMode(contentsUri);
}
return new DirectoryLoader(
@@ -1525,6 +1543,7 @@
case TYPE_RECENT_OPEN:
final RootsCache roots = DocumentsApplication.getRootsCache(context);
return new RecentsLoader(context, roots, state);
+
default:
throw new IllegalStateException("Unknown type " + mType);
}
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/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index f99ec85c..adaa850 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -82,6 +82,12 @@
abstract void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch);
/**
+ * When managed mode is enabled, active downloads will be visible in the UI.
+ * Presumably this should only be true when in the downloads directory.
+ */
+ abstract boolean enableManagedMode();
+
+ /**
* Provides support for Platform specific specializations of DirectoryFragment.
*/
private static final class DocumentsTuner extends FragmentTuner {
@@ -157,6 +163,11 @@
((BaseActivity) mContext).setRootsDrawerOpen(true);
}
}
+
+ @Override
+ public boolean enableManagedMode() {
+ return false;
+ }
}
/**
@@ -166,6 +177,7 @@
public DownloadsTuner(Context context, State state) {
super(context, state);
+ assert(state.action == ACTION_MANAGE);
}
@Override
@@ -192,6 +204,11 @@
@Override
void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {}
+
+ @Override
+ public boolean enableManagedMode() {
+ return mState.stack.root != null && mState.stack.root.isDownloads();
+ }
}
/**
@@ -233,6 +250,17 @@
((BaseActivity) mContext).setRootsDrawerOpen(true);
}
}
+
+ @Override
+ public boolean enableManagedMode() {
+ // When in downloads top level directory, we also show active downloads.
+ // And while we don't allow folders in Downloads, we do allow Zip files in
+ // downloads that themselves can be opened and viewed like directories.
+ // This method helps us understand when to kick in on those special behaviors.
+ return mState.stack.root != null
+ && mState.stack.root.isDownloads()
+ && mState.stack.size() == 1;
+ }
}
private static boolean isDirectory(String mimeType) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
index 11f9aa71..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/Model.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
index 5e55e1a..8170e2a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
@@ -64,6 +64,7 @@
@Nullable String info;
@Nullable String error;
+ @Nullable DocumentInfo doc;
/**
* Generates a Model ID for a cursor entry that refers to a document. The Model ID is a unique
@@ -111,6 +112,7 @@
mPositions.clear();
info = null;
error = null;
+ doc = null;
mIsLoading = false;
notifyUpdateListeners();
return;
@@ -125,6 +127,7 @@
mCursor = result.cursor;
mCursorCount = mCursor.getCount();
mSortOrder = result.sortOrder;
+ doc = result.doc;
updateModelData();
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 3897058..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() {
@@ -283,10 +298,6 @@
return (flags & Root.FLAG_SUPPORTS_SEARCH) != 0;
}
- public boolean isAdvanced() {
- return (flags & Root.FLAG_ADVANCED) != 0;
- }
-
public boolean isLocalOnly() {
return (flags & Root.FLAG_LOCAL_ONLY) != 0;
}
@@ -295,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);
@@ -362,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/Android.mk b/packages/DocumentsUI/tests/Android.mk
index b65ac98..3983f78 100644
--- a/packages/DocumentsUI/tests/Android.mk
+++ b/packages/DocumentsUI/tests/Android.mk
@@ -7,8 +7,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 mockito-target ub-uiautomator
+LOCAL_JAVA_LIBRARIES := android-support-v4 android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ub-uiautomator
LOCAL_PACKAGE_NAME := DocumentsUITests
LOCAL_INSTRUMENTATION_FOR := DocumentsUI
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/ActivityTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/ActivityTest.java
index 4b98aaf..683fd6c 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/ActivityTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/ActivityTest.java
@@ -32,8 +32,11 @@
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
import android.view.MotionEvent;
+import com.android.documentsui.BaseActivity;
+import com.android.documentsui.EventListener;
import com.android.documentsui.bots.DirectoryListBot;
import com.android.documentsui.bots.KeyboardBot;
import com.android.documentsui.bots.RootsListBot;
@@ -64,7 +67,6 @@
public RootInfo rootDir0;
public RootInfo rootDir1;
-
ContentResolver mResolver;
DocumentsProviderHelper mDocsHelper;
ContentProviderClient mClient;
@@ -84,6 +86,23 @@
return rootDir0;
}
+ /**
+ * Returns the authority of the testing provider begin used.
+ * By default it's StubProvider's authority.
+ * @return Authority of the provider.
+ */
+ protected String getTestingProviderAuthority() {
+ return DEFAULT_AUTHORITY;
+ }
+
+ /**
+ * Resolves testing roots.
+ */
+ protected void setupTestingRoots() throws RemoteException {
+ rootDir0 = mDocsHelper.getRoot(ROOT_0_ID);
+ rootDir1 = mDocsHelper.getRoot(ROOT_1_ID);
+ }
+
@Override
public void setUp() throws Exception {
device = UiDevice.getInstance(getInstrumentation());
@@ -95,11 +114,10 @@
Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE);
mResolver = context.getContentResolver();
- mClient = mResolver.acquireUnstableContentProviderClient(DEFAULT_AUTHORITY);
- mDocsHelper = new DocumentsProviderHelper(DEFAULT_AUTHORITY, mClient);
+ mClient = mResolver.acquireUnstableContentProviderClient(getTestingProviderAuthority());
+ mDocsHelper = new DocumentsProviderHelper(getTestingProviderAuthority(), mClient);
- rootDir0 = mDocsHelper.getRoot(ROOT_0_ID);
- rootDir1 = mDocsHelper.getRoot(ROOT_1_ID);
+ setupTestingRoots();
launchActivity();
resetStorage();
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
index 498471e..2486209 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
@@ -21,6 +21,7 @@
import android.os.RemoteException;
import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.Suppress;
import android.view.KeyEvent;
import com.android.documentsui.model.RootInfo;
@@ -139,6 +140,7 @@
}
// Tests that pressing tab switches focus between the roots and directory listings.
+ @Suppress
public void testKeyboard_tab() throws Exception {
bots.main.pressKey(KeyEvent.KEYCODE_TAB);
bots.roots.assertHasFocus();
@@ -147,6 +149,7 @@
}
// Tests that arrow keys do not switch focus away from the dir list.
+ @Suppress
public void testKeyboard_arrowsDirList() throws Exception {
for (int i = 0; i < 10; i++) {
bots.main.pressKey(KeyEvent.KEYCODE_DPAD_LEFT);
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
index 7d3498e..e73dd8c 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
@@ -16,6 +16,9 @@
package com.android.documentsui;
+import static com.android.documentsui.RootsCache.getMatchingRoots;
+import static com.google.common.collect.Lists.newArrayList;
+
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
@@ -28,23 +31,18 @@
@SmallTest
public class RootsCacheTest extends AndroidTestCase {
- private static RootInfo buildForMimeTypes(String... mimeTypes) {
- final RootInfo root = new RootInfo();
- root.derivedMimeTypes = mimeTypes;
- return root;
- }
+ private static RootInfo mNull = new RootInfo();
+ private static RootInfo mEmpty = buildForMimeTypes();
+ private static RootInfo mWild = buildForMimeTypes("*/*");
+ private static RootInfo mImages = buildForMimeTypes("image/*");
+ private static RootInfo mAudio = buildForMimeTypes(
+ "audio/*", "application/ogg", "application/x-flac");
+ private static RootInfo mDocs = buildForMimeTypes(
+ "application/msword", "application/vnd.ms-excel");
+ private static RootInfo mMalformed1 = buildForMimeTypes("meow");
+ private static RootInfo mMalformed2 = buildForMimeTypes("*/meow");
- private RootInfo mNull = new RootInfo();
- private RootInfo mEmpty = buildForMimeTypes();
- private RootInfo mWild = buildForMimeTypes("*/*");
- private RootInfo mImages = buildForMimeTypes("image/*");
- private RootInfo mAudio = buildForMimeTypes("audio/*", "application/ogg", "application/x-flac");
- private RootInfo mDocs = buildForMimeTypes("application/msword", "application/vnd.ms-excel");
- private RootInfo mMalformed1 = buildForMimeTypes("meow");
- private RootInfo mMalformed2 = buildForMimeTypes("*/meow");
-
- private List<RootInfo> mRoots = Lists.newArrayList(
- mNull, mWild, mEmpty, mImages, mAudio, mDocs, mMalformed1, mMalformed2);
+ private List<RootInfo> mRoots;
private State mState;
@@ -52,70 +50,86 @@
protected void setUp() throws Exception {
super.setUp();
+ mRoots = Lists.newArrayList(
+ mNull, mWild, mEmpty, mImages, mAudio, mDocs, mMalformed1, mMalformed2);
+
mState = new State();
mState.action = State.ACTION_OPEN;
- mState.showAdvanced = true;
mState.localOnly = false;
}
- public void testMatchingRootsEverything() throws Exception {
+ public void testMatchingRoots_Everything() throws Exception {
mState.acceptMimes = new String[] { "*/*" };
assertContainsExactly(
- Lists.newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
- RootsCache.getMatchingRoots(mRoots, mState));
+ newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
+ getMatchingRoots(mRoots, mState));
}
- public void testMatchingRootsPngOrWild() throws Exception {
+ public void testMatchingRoots_DirectoryCopy() throws Exception {
+ RootInfo downloads = buildForMimeTypes("*/*");
+ downloads.authority = "com.android.providers.downloads.documents";
+ mRoots.add(downloads);
+
+ mState.acceptMimes = new String[] { "*/*" };
+ mState.directoryCopy = true;
+
+ // basically we're asserting that the results don't contain downloads
+ assertContainsExactly(
+ newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
+ getMatchingRoots(mRoots, mState));
+ }
+
+ public void testMatchingRoots_PngOrWild() throws Exception {
mState.acceptMimes = new String[] { "image/png", "*/*" };
assertContainsExactly(
- Lists.newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
- RootsCache.getMatchingRoots(mRoots, mState));
+ newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
+ getMatchingRoots(mRoots, mState));
}
- public void testMatchingRootsAudioWild() throws Exception {
+ public void testMatchingRoots_AudioWild() throws Exception {
mState.acceptMimes = new String[] { "audio/*" };
assertContainsExactly(
- Lists.newArrayList(mNull, mWild, mAudio),
- RootsCache.getMatchingRoots(mRoots, mState));
+ newArrayList(mNull, mWild, mAudio),
+ getMatchingRoots(mRoots, mState));
}
- public void testMatchingRootsAudioWildOrImageWild() throws Exception {
+ public void testMatchingRoots_AudioWildOrImageWild() throws Exception {
mState.acceptMimes = new String[] { "audio/*", "image/*" };
assertContainsExactly(
- Lists.newArrayList(mNull, mWild, mAudio, mImages),
- RootsCache.getMatchingRoots(mRoots, mState));
+ newArrayList(mNull, mWild, mAudio, mImages),
+ getMatchingRoots(mRoots, mState));
}
- public void testMatchingRootsAudioSpecific() throws Exception {
+ public void testMatchingRoots_AudioSpecific() throws Exception {
mState.acceptMimes = new String[] { "audio/mpeg" };
assertContainsExactly(
- Lists.newArrayList(mNull, mWild, mAudio),
- RootsCache.getMatchingRoots(mRoots, mState));
+ newArrayList(mNull, mWild, mAudio),
+ getMatchingRoots(mRoots, mState));
}
- public void testMatchingRootsDocument() throws Exception {
+ public void testMatchingRoots_Document() throws Exception {
mState.acceptMimes = new String[] { "application/msword" };
assertContainsExactly(
- Lists.newArrayList(mNull, mWild, mDocs),
- RootsCache.getMatchingRoots(mRoots, mState));
+ newArrayList(mNull, mWild, mDocs),
+ getMatchingRoots(mRoots, mState));
}
- public void testMatchingRootsApplication() throws Exception {
+ public void testMatchingRoots_Application() throws Exception {
mState.acceptMimes = new String[] { "application/*" };
assertContainsExactly(
- Lists.newArrayList(mNull, mWild, mAudio, mDocs),
- RootsCache.getMatchingRoots(mRoots, mState));
+ newArrayList(mNull, mWild, mAudio, mDocs),
+ getMatchingRoots(mRoots, mState));
}
- public void testMatchingRootsFlacOrPng() throws Exception {
+ public void testMatchingRoots_FlacOrPng() throws Exception {
mState.acceptMimes = new String[] { "application/x-flac", "image/png" };
assertContainsExactly(
- Lists.newArrayList(mNull, mWild, mAudio, mImages),
- RootsCache.getMatchingRoots(mRoots, mState));
+ newArrayList(mNull, mWild, mAudio, mImages),
+ getMatchingRoots(mRoots, mState));
}
public void testExcludedAuthorities() throws Exception {
- final List<RootInfo> roots = Lists.newArrayList();
+ final List<RootInfo> roots = newArrayList();
// Set up some roots
for (int i = 0; i < 5; ++i) {
@@ -124,7 +138,7 @@
roots.add(root);
}
// Make some allowed authorities
- List<RootInfo> allowedRoots = Lists.newArrayList(
+ List<RootInfo> allowedRoots = newArrayList(
roots.get(0), roots.get(2), roots.get(4));
// Set up the excluded authority list
for (RootInfo root: roots) {
@@ -136,7 +150,7 @@
assertContainsExactly(
allowedRoots,
- RootsCache.getMatchingRoots(roots, mState));
+ getMatchingRoots(roots, mState));
}
private static void assertContainsExactly(List<?> expected, List<?> actual) {
@@ -145,4 +159,10 @@
assertTrue(actual.contains(o));
}
}
+
+ private static RootInfo buildForMimeTypes(String... mimeTypes) {
+ final RootInfo root = new RootInfo();
+ root.derivedMimeTypes = mimeTypes;
+ return root;
+ }
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsUiTest.java
index 73c1c5f..621410a 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsUiTest.java
@@ -20,6 +20,7 @@
import static com.android.documentsui.StubProvider.ROOT_1_ID;
import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.Suppress;
@LargeTest
public class RootsUiTest extends ActivityTest<FilesActivity> {
@@ -44,6 +45,7 @@
assertDefaultContentOfTestDir0();
}
+ @Suppress
public void testRootChanged_ClearSelection() throws Exception {
bots.directory.selectDocument(fileName1);
bots.main.assertInActionMode(true);
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
index 8c3fd90..a9451a6 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
@@ -20,6 +20,7 @@
import static com.android.documentsui.StubProvider.ROOT_1_ID;
import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.Suppress;
@LargeTest
public class SearchViewUiTest extends ActivityTest<FilesActivity> {
@@ -28,6 +29,7 @@
super(FilesActivity.class);
}
+ @Suppress
public void testSearchView_ExpandsOnClick() throws Exception {
bots.main.openSearchView();
bots.main.assertSearchTextFiledAndIcon(true, false);
@@ -41,6 +43,7 @@
bots.main.assertSearchTextFiledAndIcon(false, true);
}
+ @Suppress
public void testSearchView_ClearsTextOnBack() throws Exception {
String query = "file2";
bots.main.openSearchView();
@@ -51,6 +54,7 @@
bots.main.assertSearchTextFiledAndIcon(false, true);
}
+ @Suppress
public void testSearch_ResultsFound() throws Exception {
initTestFiles();
assertDefaultContentOfTestDir0();
@@ -68,6 +72,7 @@
bots.main.assertSearchTextField(false, query);
}
+ @Suppress
public void testSearchResultsFound_ClearsOnBack() throws Exception {
initTestFiles();
assertDefaultContentOfTestDir0();
@@ -82,6 +87,7 @@
assertDefaultContentOfTestDir0();
}
+ @Suppress
public void testSearch_NoResults() throws Exception {
initTestFiles();
assertDefaultContentOfTestDir0();
@@ -101,6 +107,7 @@
bots.main.assertSearchTextField(false, query);
}
+ @Suppress
public void testSearchNoResults_ClearsOnBack() throws Exception {
initTestFiles();
assertDefaultContentOfTestDir0();
@@ -116,6 +123,7 @@
assertDefaultContentOfTestDir0();
}
+ @Suppress
public void testSearchResultsFound_ClearsOnDirectoryChange() throws Exception {
initTestFiles();
assertDefaultContentOfTestDir0();
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 97527dd..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,10 +185,17 @@
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;
- root.flags |= Root.FLAG_ADVANCED;
}
// Dunno when this would NOT be the case, but never hurts to be correct.
if (volume.isMountedWritable()) {
@@ -193,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;
@@ -211,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/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
index 044a061..0705214 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
@@ -276,7 +276,7 @@
static final int STATE_ERROR = 2;
final MtpDatabase mDatabase;
- int[] mOperationsSupported;
+ final int[] mOperationsSupported;
final Identifier mIdentifier;
final int[] mObjectHandles;
Date mLastNotified;
@@ -285,6 +285,8 @@
LoaderTask(MtpDatabase database, int[] operationsSupported, Identifier identifier,
int[] objectHandles) {
+ Preconditions.checkNotNull(operationsSupported);
+ Preconditions.checkNotNull(objectHandles);
mDatabase = database;
mOperationsSupported = operationsSupported;
mIdentifier = identifier;
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index c031f34..7211253 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -440,7 +440,7 @@
if (DEBUG) {
Log.d(TAG, "Close device " + deviceId);
}
- getDeviceToolkit(deviceId).mDocumentLoader.close();
+ getDeviceToolkit(deviceId).close();
mDeviceToolkits.remove(deviceId);
mMtpManager.closeDevice(deviceId);
if (mDeviceToolkits.size() == 0) {
@@ -496,7 +496,7 @@
return cursor;
}
- private static class DeviceToolkit {
+ private static class DeviceToolkit implements AutoCloseable {
public final PipeManager mPipeManager;
public final DocumentLoader mDocumentLoader;
public final MtpDeviceRecord mDeviceRecord;
@@ -509,6 +509,12 @@
mDocumentLoader = new DocumentLoader(record, manager, resolver, database);
mDeviceRecord = record;
}
+
+ @Override
+ public void close() throws InterruptedException {
+ mPipeManager.close();
+ mDocumentLoader.close();
+ }
}
private class AppFuseCallback implements AppFuse.Callback {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 1966e61..0202343 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -143,7 +143,12 @@
throws IOException {
final MtpDevice device = getDevice(deviceId);
synchronized (device) {
- return device.getObjectHandles(storageId, 0 /* all format */, parentObjectHandle);
+ final int[] handles =
+ device.getObjectHandles(storageId, 0 /* all format */, parentObjectHandle);
+ if (handles == null) {
+ throw new IOException("Failed to fetch object handles.");
+ }
+ return handles;
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
index 73042c4..c10a65e 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
@@ -26,8 +26,14 @@
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
class PipeManager {
+ /**
+ * Milliseconds we wait for background thread when pausing.
+ */
+ private final static long AWAIT_TERMINATION_TIMEOUT = 2000;
+
final ExecutorService mExecutor;
final MtpDatabase mDatabase;
@@ -203,7 +209,8 @@
}
}
- void close() {
- mExecutor.shutdown();
+ boolean close() throws InterruptedException {
+ mExecutor.shutdownNow();
+ return mExecutor.awaitTermination(AWAIT_TERMINATION_TIMEOUT, TimeUnit.MILLISECONDS);
}
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 3dfa4ad..d6ad0f3 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -596,7 +596,7 @@
0,
"Device A",
"device key",
- true /* unopened */,
+ true /* opened */,
new MtpRoot[] {
new MtpRoot(
0 /* deviceId */,
@@ -606,7 +606,7 @@
2048 /* total space */,
"" /* no volume identifier */)
},
- null,
+ OPERATIONS_SUPPORTED,
null));
final String[] names = strings("Directory A", "Directory B", "Directory C");
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
index 919ac39..cdddd81 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
@@ -45,6 +45,11 @@
mPipeManager = new PipeManager(mDatabase, mExecutor);
}
+ @Override
+ protected void tearDown() throws Exception {
+ assertTrue(mPipeManager.close());
+ }
+
public void testReadDocument_basic() throws Exception {
mtpManager.setImportFileBytes(0, 1, HELLO_BYTES);
final ParcelFileDescriptor descriptor = mPipeManager.readDocument(
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
index 5e0ee1e..5171bd2 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
@@ -106,7 +106,7 @@
mDevices.put(
deviceId,
new MtpDeviceRecord(device.deviceId, device.name, device.deviceKey, false,
- device.roots, null, null));
+ device.roots, device.operationsSupported, device.eventsSupported));
}
@Override
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index af9d251..1bdb6d8 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -63,7 +63,7 @@
android:name=".ui.PrintActivity"
android:configChanges="screenSize|smallestScreenSize|orientation"
android:permission="android.permission.BIND_PRINT_SPOOLER_SERVICE"
- android:theme="@style/PrintActivity">
+ android:theme="@style/Theme.PrintActivity">
<intent-filter>
<action android:name="android.print.PRINT_DIALOG" />
<category android:name="android.intent.category.DEFAULT" />
@@ -74,7 +74,14 @@
<activity
android:name=".ui.SelectPrinterActivity"
android:label="@string/all_printers_label"
- android:theme="@android:style/Theme.Material.Settings"
+ android:theme="@style/Theme.SelectPrinterActivity"
+ android:exported="false">
+ </activity>
+
+ <activity
+ android:name=".ui.AddPrinterActivity"
+ android:label="@string/print_add_printer"
+ android:theme="@style/Theme.AddPrinterActivity"
android:exported="false">
</activity>
diff --git a/packages/PrintSpooler/res/drawable/ic_add.xml b/packages/PrintSpooler/res/drawable/ic_add.xml
index 1442b1b..f728e7d 100644
--- a/packages/PrintSpooler/res/drawable/ic_add.xml
+++ b/packages/PrintSpooler/res/drawable/ic_add.xml
@@ -21,5 +21,5 @@
android:viewportHeight="24.0">
<path
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"
- android:fillColor="#FFFFFF"/>
+ android:fillColor="?android:attr/colorAccent"/>
</vector>
\ No newline at end of file
diff --git a/packages/PrintSpooler/res/drawable/ic_print.xml b/packages/PrintSpooler/res/drawable/ic_print.xml
index dc6e0fb..e5e4d075 100644
--- a/packages/PrintSpooler/res/drawable/ic_print.xml
+++ b/packages/PrintSpooler/res/drawable/ic_print.xml
@@ -16,4 +16,4 @@
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@*android:drawable/ic_print"
- android:tint="@color/promoted_action_background_color" />
+ android:tint="?android:attr/colorAccent" />
diff --git a/packages/PrintSpooler/res/drawable/page_selector_background.xml b/packages/PrintSpooler/res/drawable/page_selector_background.xml
index 7f1da31..4d32328 100644
--- a/packages/PrintSpooler/res/drawable/page_selector_background.xml
+++ b/packages/PrintSpooler/res/drawable/page_selector_background.xml
@@ -22,14 +22,14 @@
android:state_selected="true">
<bitmap
android:src="@drawable/ic_check_circle"
- android:tint="@color/promoted_action_background_color">
+ android:tint="?android:attr/colorAccent">
</bitmap>
</item>
<item>
<bitmap
android:src="@drawable/ic_remove_circle"
- android:tint="@color/promoted_action_background_color">
+ android:tint="?android:attr/colorAccent">
</bitmap>
</item>
diff --git a/packages/PrintSpooler/res/drawable/print_button_background.xml b/packages/PrintSpooler/res/drawable/print_button_background.xml
index aec8474..ad16547 100644
--- a/packages/PrintSpooler/res/drawable/print_button_background.xml
+++ b/packages/PrintSpooler/res/drawable/print_button_background.xml
@@ -18,7 +18,7 @@
android:shape="oval">
<solid
- android:color="@color/promoted_action_background_color">
+ android:color="?android:attr/colorAccent">
</solid>
<size
diff --git a/packages/PrintSpooler/res/layout/add_printer_activity.xml b/packages/PrintSpooler/res/layout/add_printer_activity.xml
new file mode 100644
index 0000000..117bba1
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/add_printer_activity.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingTop="16dip"
+ android:paddingBottom="16dip">
+
+ <ListView android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-16dip"
+ android:id="@android:id/list" />
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/add_printer_list_header.xml b/packages/PrintSpooler/res/layout/add_printer_list_header.xml
new file mode 100644
index 0000000..ff342cb
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/add_printer_list_header.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeightSmall"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:orientation="horizontal"
+ android:gravity="start|center_vertical">
+
+ <TextView android:id="@+id/text"
+ style="?android:attr/listSeparatorTextViewStyle" />
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/add_printer_list_item.xml b/packages/PrintSpooler/res/layout/add_printer_list_item.xml
new file mode 100644
index 0000000..1a2e774
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/add_printer_list_item.xml
@@ -0,0 +1,46 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeightSmall"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:orientation="horizontal"
+ android:gravity="start|center_vertical">
+
+ <ImageView
+ android:layout_width="24dip"
+ android:layout_height="24dip"
+ android:layout_gravity="center_vertical"
+ android:contentDescription="@null"
+ android:layout_marginEnd="16dip"
+ android:src="@drawable/ic_add" />
+
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dip">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:text="@string/print_add_printer" />
+
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/all_print_services_list_item.xml b/packages/PrintSpooler/res/layout/all_print_services_list_item.xml
new file mode 100644
index 0000000..a2471c6
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/all_print_services_list_item.xml
@@ -0,0 +1,38 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeightSmall"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:orientation="horizontal"
+ android:gravity="start|center_vertical">
+
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="56dip">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:text="@string/all_services_title" />
+
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/disabled_print_services_list_item.xml b/packages/PrintSpooler/res/layout/disabled_print_services_list_item.xml
new file mode 100644
index 0000000..73d0933
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/disabled_print_services_list_item.xml
@@ -0,0 +1,55 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:orientation="horizontal"
+ android:gravity="start|center_vertical">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="40dip"
+ android:layout_height="40dip"
+ android:layout_gravity="center_vertical"
+ android:contentDescription="@null" />
+
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dip">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:singleLine="true"
+ android:ellipsize="end" />
+
+ <TextView
+ android:id="@+id/subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/title"
+ android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+ android:text="@string/enable_print_service" />
+
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/enabled_print_services_list_item.xml b/packages/PrintSpooler/res/layout/enabled_print_services_list_item.xml
new file mode 100644
index 0000000..c13487a
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/enabled_print_services_list_item.xml
@@ -0,0 +1,54 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:orientation="horizontal"
+ android:gravity="start|center_vertical">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="40dip"
+ android:layout_height="40dip"
+ android:layout_gravity="center_vertical"
+ android:contentDescription="@null" />
+
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dip">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:singleLine="true"
+ android:ellipsize="end" />
+
+ <TextView
+ android:id="@+id/subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/title"
+ android:textAppearance="?android:attr/textAppearanceListItemSecondary" />
+
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
index defbf8d..103c157 100644
--- a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
+++ b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
@@ -16,10 +16,8 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:paddingStart="8dip"
- android:paddingEnd="8dip"
- android:minHeight="56dip"
+ android:layout_height="?android:attr/listPreferredItemHeightSmall"
+ style="?android:attr/spinnerItemStyle"
android:orientation="horizontal"
android:gravity="start|center_vertical">
@@ -33,10 +31,9 @@
android:visibility="invisible">
</ImageView>
- <LinearLayout
+ <RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="vertical"
android:layout_marginStart="8dip"
android:duplicateParentState="true">
@@ -47,8 +44,6 @@
android:textAppearance="?android:attr/textAppearanceMedium"
android:singleLine="true"
android:ellipsize="end"
- android:textIsSelectable="false"
- android:gravity="top|start"
android:textColor="?android:attr/textColorPrimary"
android:duplicateParentState="true">
</TextView>
@@ -57,15 +52,15 @@
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_below="@id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:singleLine="true"
android:ellipsize="end"
- android:textIsSelectable="false"
android:visibility="gone"
android:textColor="?android:attr/textColorSecondary"
android:duplicateParentState="true">
</TextView>
- </LinearLayout>
+ </RelativeLayout>
</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/printer_dropdown_prompt.xml b/packages/PrintSpooler/res/layout/printer_dropdown_prompt.xml
index 11fef2d..60f7088 100644
--- a/packages/PrintSpooler/res/layout/printer_dropdown_prompt.xml
+++ b/packages/PrintSpooler/res/layout/printer_dropdown_prompt.xml
@@ -16,13 +16,10 @@
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
- android:layout_height="wrap_content"
+ android:layout_height="?android:attr/listPreferredItemHeightSmall"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textIsSelectable="false"
android:textColor="?android:attr/textColorPrimary"
android:paddingStart="20dip"
- android:paddingEnd="8dip"
- android:minHeight="56dip"
- android:orientation="horizontal"
+ style="?android:attr/spinnerItemStyle"
android:text="@string/destination_default_text"
android:gravity="start|center_vertical" />
diff --git a/packages/PrintSpooler/res/layout/printer_list_item.xml b/packages/PrintSpooler/res/layout/printer_list_item.xml
index 1209aa6..0784bab 100644
--- a/packages/PrintSpooler/res/layout/printer_list_item.xml
+++ b/packages/PrintSpooler/res/layout/printer_list_item.xml
@@ -16,10 +16,9 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
- android:layout_height="wrap_content"
+ android:layout_height="?android:attr/listPreferredItemHeight"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
android:gravity="start|center_vertical">
@@ -28,18 +27,15 @@
android:layout_width="40dip"
android:layout_height="40dip"
android:layout_gravity="center_vertical"
- android:layout_marginTop="8dip"
- android:layout_marginBottom="8dip"
android:duplicateParentState="true"
android:contentDescription="@null"
android:visibility="invisible">
</ImageView>
<RelativeLayout
- android:layout_width="0dip"
+ android:layout_width="fill_parent"
android:layout_weight="1"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
android:layout_marginStart="16dip"
android:duplicateParentState="true">
@@ -47,15 +43,9 @@
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textAppearance="?android:attr/textAppearanceListItem"
android:singleLine="true"
android:ellipsize="end"
- android:textIsSelectable="false"
- android:layout_alignParentTop="true"
- android:layout_alignParentStart="true"
- android:fadingEdge="horizontal"
- android:textAlignment="viewStart"
- android:textColor="?android:attr/textColorPrimary"
android:duplicateParentState="true">
</TextView>
@@ -64,30 +54,31 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/title"
- android:layout_alignParentStart="true"
- android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:singleLine="true"
android:ellipsize="end"
- android:textIsSelectable="false"
android:visibility="gone"
- android:textColor="?android:attr/textColorSecondary"
- android:textAlignment="viewStart"
android:duplicateParentState="true">
</TextView>
</RelativeLayout>
- <ImageView
+ <!-- wrapper for image view to increase the touch target size -->
+ <LinearLayout
android:id="@+id/more_info"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:paddingLeft="16dip"
- android:contentDescription="@string/printer_info_desc"
- android:src="@drawable/ic_info"
- android:tint="?android:attr/colorControlNormal"
- android:tintMode="src_in"
+ android:layout_height="fill_parent"
android:visibility="gone">
- </ImageView>
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingLeft="16dip"
+ android:contentDescription="@string/printer_info_desc"
+ android:src="@drawable/ic_info"
+ android:tint="?android:attr/colorControlNormal"
+ android:tintMode="src_in" />
+ </LinearLayout>
</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/select_printer_activity.xml b/packages/PrintSpooler/res/layout/select_printer_activity.xml
index 77c500a..564802a 100644
--- a/packages/PrintSpooler/res/layout/select_printer_activity.xml
+++ b/packages/PrintSpooler/res/layout/select_printer_activity.xml
@@ -22,11 +22,7 @@
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:scrollbarStyle="outsideOverlay"
- android:cacheColorHint="@android:color/transparent"
- android:scrollbarAlwaysDrawVerticalTrack="true" >
- </ListView>
+ android:layout_height="fill_parent" />
<FrameLayout
android:id="@+id/empty_print_state"
@@ -63,9 +59,18 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
- style="@android:style/Widget.DeviceDefault.Light.ProgressBar.Horizontal">
+ style="?android:attr/progressBarStyleHorizontal">
</ProgressBar>
+ <Button
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="?android:attr/buttonBarButtonStyle"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text="@string/print_add_printer"
+ android:textAllCaps="true" />
+
</LinearLayout>
</FrameLayout>
diff --git a/packages/PrintSpooler/res/menu/select_printer_activity.xml b/packages/PrintSpooler/res/menu/select_printer_activity.xml
index 15cc139..60dfdca 100644
--- a/packages/PrintSpooler/res/menu/select_printer_activity.xml
+++ b/packages/PrintSpooler/res/menu/select_printer_activity.xml
@@ -26,12 +26,4 @@
android:imeOptions="actionSearch">
</item>
- <item
- android:id="@+id/action_add_printer"
- android:title="@string/print_add_printer"
- android:icon="@drawable/ic_add"
- android:showAsAction="ifRoom"
- android:alphabeticShortcut="a">
- </item>
-
</menu>
diff --git a/packages/PrintSpooler/res/values/colors.xml b/packages/PrintSpooler/res/values/colors.xml
index d1bec32..47e616e 100644
--- a/packages/PrintSpooler/res/values/colors.xml
+++ b/packages/PrintSpooler/res/values/colors.xml
@@ -22,8 +22,6 @@
<color name="print_preview_background_color">#F2F1F2</color>
- <color name="promoted_action_background_color">#FF80CBC4</color>
-
<color name="material_grey_500">#ffa3a3a3</color>
</resources>
diff --git a/packages/PrintSpooler/res/values/donottranslate.xml b/packages/PrintSpooler/res/values/donottranslate.xml
index 8069a1d..589043b 100644
--- a/packages/PrintSpooler/res/values/donottranslate.xml
+++ b/packages/PrintSpooler/res/values/donottranslate.xml
@@ -25,4 +25,6 @@
<string name="mediasize_default">ISO_A4</string>
<string name="mediasize_standard">@string/mediasize_standard_iso</string>
+ <string name="uri_package_details">market://details?id=%1$s</string>
+
</resources>
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 76292a1..4b56622 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -129,7 +129,7 @@
<!-- Utterance to announce that the search box is hidden. This is spoken to a blind user. [CHAR LIMIT=none] -->
<string name="print_search_box_hidden_utterance">Search box hidden</string>
- <!-- Title of the action bar button to got to add a printer. [CHAR LIMIT=25] -->
+ <!-- Label of add printers button when no printers are found. [CHAR LIMIT=25] -->
<string name="print_add_printer">Add printer</string>
<!-- Title of the menu item to select a printer. [CHAR LIMIT=25] -->
@@ -151,12 +151,7 @@
<string name="printer_info_desc">More information about this printer</string>
<!-- Notification that print services as disabled. [CHAR LIMIT=50] -->
- <string name="print_services_disabled_toast">Some print services are disabled.</string>
-
- <!-- Add printer dialog -->
-
- <!-- Title for the alert dialog for selecting a print service. [CHAR LIMIT=50] -->
- <string name="choose_print_service">Choose print service</string>
+ <string name="print_services_disabled_toast">Some print services are disabled</string>
<!-- Title for the prompt shown as a placeholder if no printers are found while not searching. [CHAR LIMIT=50] -->
<string name="print_searching_for_printers">Searching for printers</string>
@@ -167,6 +162,29 @@
<!-- Title for the prompt shown as a placeholder if there are no printers while searching. [CHAR LIMIT=50] -->
<string name="print_no_printers">No printers found</string>
+ <!-- Add printer activity -->
+
+ <!-- Subtitle for services that cannot add printers. [CHAR LIMIT=50] -->
+ <string name="cannot_add_printer">Cannot add printers</string>
+
+ <!-- Subtitle for services that can add printers. [CHAR LIMIT=50] -->
+ <string name="select_to_add_printers">Select to add printer</string>
+
+ <!-- Subtitle for disabled services. [CHAR LIMIT=50] -->
+ <string name="enable_print_service">Select to enable</string>
+
+ <!-- Header for the list of enabled print services. [CHAR LIMIT=50] -->
+ <string name="enabled_services_title">Enabled services</string>
+
+ <!-- Header for the list of recommended print services. [CHAR LIMIT=50] -->
+ <string name="recommended_services_title">Recommended services</string>
+
+ <!-- Header for the list of disabled print services. [CHAR LIMIT=50] -->
+ <string name="disabled_services_title">Disabled services</string>
+
+ <!-- Label for the list item that links to the list of all print services. [CHAR LIMIT=50] -->
+ <string name="all_services_title">All services</string>
+
<!-- Notifications -->
<!-- Template for the notification label for a printing print job. [CHAR LIMIT=25] -->
diff --git a/packages/PrintSpooler/res/values/styles.xml b/packages/PrintSpooler/res/values/styles.xml
new file mode 100644
index 0000000..1e63a67e
--- /dev/null
+++ b/packages/PrintSpooler/res/values/styles.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<resources>
+ <!-- Preference styles -->
+ <eat-comment/>
+
+ <style name="ListItemSecondary" parent="@android:style/TextAppearance.Material.Body1">
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ </style>
+
+ <style name="ListSeparator">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginTop">16dip</item>
+ <item name="android:layout_marginBottom">16dip</item>
+ <item name="android:textColor">?android:attr/colorAccent</item>
+ <item name="android:fontFamily">sans-serif-medium</item>
+ <item name="android:textSize">14sp</item>
+ </style>
+</resources>
diff --git a/packages/PrintSpooler/res/values/themes.xml b/packages/PrintSpooler/res/values/themes.xml
index 05de5b7..a968ffa 100644
--- a/packages/PrintSpooler/res/values/themes.xml
+++ b/packages/PrintSpooler/res/values/themes.xml
@@ -15,8 +15,17 @@
-->
<resources>
+ <style name="Theme.AddPrinterActivity" parent="@android:style/Theme.DeviceDefault.Light.Dialog">
+ <item name="android:listSeparatorTextViewStyle">@style/ListSeparator</item>
+ <item name="android:textAppearanceListItemSecondary">@style/ListItemSecondary</item>
+ </style>
- <style name="PrintActivity" parent="@android:style/Theme.DeviceDefault">
+ <style name="Theme.SelectPrinterActivity"
+ parent="android:style/Theme.DeviceDefault.Light.DarkActionBar">
+ <item name="android:textAppearanceListItemSecondary">@style/ListItemSecondary</item>
+ </style>
+
+ <style name="Theme.PrintActivity" parent="@android:style/Theme.DeviceDefault">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
index ac97ad0..f8b1343 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
@@ -862,6 +862,9 @@
// Take a note that the content is rendered.
renderedPage.state = RenderedPage.STATE_RENDERED;
+ // Invalidate all caches of the old state of the bitmap
+ mRenderedPage.content.invalidateSelf();
+
// Announce success if needed.
if (mCallback != null) {
mCallback.onPageContentAvailable(renderedPage.content);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
new file mode 100644
index 0000000..f2b3e6e
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
@@ -0,0 +1,563 @@
+/*
+ * 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.printspooler.ui;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ListActivity;
+import android.app.LoaderManager;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.Loader;
+import android.database.DataSetObserver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.print.PrintManager;
+import android.print.PrintServicesLoader;
+import android.printservice.PrintServiceInfo;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Adapter;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+import com.android.printspooler.R;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This is an activity for adding a printer or. It consists of a list fed from three adapters:
+ * <ul>
+ * <li>{@link #mEnabledServicesAdapter} for all enabled services. If a service has an {@link
+ * PrintServiceInfo#getAddPrintersActivityName() add printer activity} this is started
+ * when the item is clicked.</li>
+ * <li>{@link #mDisabledServicesAdapter} for all disabled services. Once clicked the settings page
+ * for this service is opened.</li>
+ * <li>{@link RecommendedServicesAdapter} for a link to all services. If this item is clicked
+ * the market app is opened to show all print services.</li>
+ * </ul>
+ */
+public class AddPrinterActivity extends ListActivity implements
+ LoaderManager.LoaderCallbacks<List<PrintServiceInfo>>,
+ AdapterView.OnItemClickListener {
+ private static final String LOG_TAG = "AddPrinterActivity";
+
+ /** Ids for the loaders */
+ private static final int LOADER_ID_ENABLED_SERVICES = 1;
+ private static final int LOADER_ID_DISABLED_SERVICES = 2;
+
+ /**
+ * The enabled services list. This is filled from the {@link #LOADER_ID_ENABLED_SERVICES}
+ * loader in {@link #onLoadFinished}.
+ */
+ private EnabledServicesAdapter mEnabledServicesAdapter;
+
+ /**
+ * The disabled services list. This is filled from the {@link #LOADER_ID_DISABLED_SERVICES}
+ * loader in {@link #onLoadFinished}.
+ */
+ private DisabledServicesAdapter mDisabledServicesAdapter;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.add_printer_activity);
+
+ mEnabledServicesAdapter = new EnabledServicesAdapter();
+ mDisabledServicesAdapter = new DisabledServicesAdapter();
+
+ ArrayList<ActionAdapter> adapterList = new ArrayList<>(3);
+ adapterList.add(mEnabledServicesAdapter);
+ adapterList.add(new RecommendedServicesAdapter());
+ adapterList.add(mDisabledServicesAdapter);
+
+ setListAdapter(new CombinedAdapter(adapterList));
+
+ getListView().setOnItemClickListener(this);
+
+ getLoaderManager().initLoader(LOADER_ID_ENABLED_SERVICES, null, this);
+ getLoaderManager().initLoader(LOADER_ID_DISABLED_SERVICES, null, this);
+ // TODO: Load recommended services
+ }
+
+ @Override
+ public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) {
+ switch (id) {
+ case LOADER_ID_ENABLED_SERVICES:
+ return new PrintServicesLoader(
+ (PrintManager) getSystemService(Context.PRINT_SERVICE), this,
+ PrintManager.ENABLED_SERVICES);
+ case LOADER_ID_DISABLED_SERVICES:
+ return new PrintServicesLoader(
+ (PrintManager) getSystemService(Context.PRINT_SERVICE), this,
+ PrintManager.DISABLED_SERVICES);
+ // TODO: Load recommended services
+ default:
+ // not reached
+ return null;
+ }
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ ((ActionAdapter) getListAdapter()).performAction(position);
+ }
+
+ @Override
+ public void onLoadFinished(Loader<List<PrintServiceInfo>> loader,
+ List<PrintServiceInfo> data) {
+ switch (loader.getId()) {
+ case LOADER_ID_ENABLED_SERVICES:
+ mEnabledServicesAdapter.updateData(data);
+ break;
+ case LOADER_ID_DISABLED_SERVICES:
+ mDisabledServicesAdapter.updateData(data);
+ break;
+ // TODO: Load recommended services
+ default:
+ // not reached
+ }
+ }
+
+ @Override
+ public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
+ if (!isFinishing()) {
+ switch (loader.getId()) {
+ case LOADER_ID_ENABLED_SERVICES:
+ mEnabledServicesAdapter.updateData(null);
+ break;
+ case LOADER_ID_DISABLED_SERVICES:
+ mDisabledServicesAdapter.updateData(null);
+ break;
+ // TODO: Reset recommended services
+ default:
+ // not reached
+ }
+ }
+ }
+
+ /**
+ * Marks an adapter that can can perform an action for a position in it's list.
+ */
+ private abstract class ActionAdapter extends BaseAdapter {
+ /**
+ * Perform the action for a position in the list.
+ *
+ * @param position The position of the item
+ */
+ abstract void performAction(@IntRange(from = 0) int position);
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return false;
+ }
+ }
+
+ /**
+ * An adapter presenting multiple sub adapters as a single combined adapter.
+ */
+ private class CombinedAdapter extends ActionAdapter {
+ /** The adapters to combine */
+ private final @NonNull ArrayList<ActionAdapter> mAdapters;
+
+ /**
+ * Create a combined adapter.
+ *
+ * @param adapters the list of adapters to combine
+ */
+ CombinedAdapter(@NonNull ArrayList<ActionAdapter> adapters) {
+ mAdapters = adapters;
+
+ final int numAdapters = mAdapters.size();
+ for (int i = 0; i < numAdapters; i++) {
+ mAdapters.get(i).registerDataSetObserver(new DataSetObserver() {
+ @Override
+ public void onChanged() {
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public void onInvalidated() {
+ notifyDataSetChanged();
+ }
+ });
+ }
+ }
+
+ @Override
+ public int getCount() {
+ int totalCount = 0;
+
+ final int numAdapters = mAdapters.size();
+ for (int i = 0; i < numAdapters; i++) {
+ totalCount += mAdapters.get(i).getCount();
+ }
+
+ return totalCount;
+ }
+
+ /**
+ * Find the sub adapter and the position in the sub-adapter the position in the combined
+ * adapter refers to.
+ *
+ * @param position The position in the combined adapter
+ *
+ * @return The pair of adapter and position in sub adapter
+ */
+ private @NonNull Pair<ActionAdapter, Integer> getSubAdapter(int position) {
+ final int numAdapters = mAdapters.size();
+ for (int i = 0; i < numAdapters; i++) {
+ ActionAdapter adapter = mAdapters.get(i);
+
+ if (position < adapter.getCount()) {
+ return new Pair<>(adapter, position);
+ } else {
+ position -= adapter.getCount();
+ }
+ }
+
+ throw new IllegalArgumentException("Invalid position");
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ int numLowerViewTypes = 0;
+
+ final int numAdapters = mAdapters.size();
+ for (int i = 0; i < numAdapters; i++) {
+ Adapter adapter = mAdapters.get(i);
+
+ if (position < adapter.getCount()) {
+ return numLowerViewTypes + adapter.getItemViewType(position);
+ } else {
+ numLowerViewTypes += adapter.getViewTypeCount();
+ position -= adapter.getCount();
+ }
+ }
+
+ throw new IllegalArgumentException("Invalid position");
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ int totalViewCount = 0;
+
+ final int numAdapters = mAdapters.size();
+ for (int i = 0; i < numAdapters; i++) {
+ totalViewCount += mAdapters.get(i).getViewTypeCount();
+ }
+
+ return totalViewCount;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Pair<ActionAdapter, Integer> realPosition = getSubAdapter(position);
+
+ return realPosition.first.getView(realPosition.second, convertView, parent);
+ }
+
+ @Override
+ public Object getItem(int position) {
+ Pair<ActionAdapter, Integer> realPosition = getSubAdapter(position);
+
+ return realPosition.first.getItem(realPosition.second);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ Pair<ActionAdapter, Integer> realPosition = getSubAdapter(position);
+
+ return realPosition.first.isEnabled(realPosition.second);
+ }
+
+ @Override
+ public void performAction(@IntRange(from = 0) int position) {
+ Pair<ActionAdapter, Integer> realPosition = getSubAdapter(position);
+
+ realPosition.first.performAction(realPosition.second);
+ }
+ }
+
+ /**
+ * Superclass for all adapters that just display a list of {@link PrintServiceInfo}.
+ */
+ private abstract class PrintServiceInfoAdapter extends ActionAdapter {
+ /**
+ * Raw data of the list.
+ *
+ * @see #updateData(List)
+ */
+ private @NonNull List<PrintServiceInfo> mServices;
+
+ /**
+ * Create a new adapter.
+ */
+ PrintServiceInfoAdapter() {
+ mServices = Collections.emptyList();
+ }
+
+ /**
+ * Update the data.
+ *
+ * @param services The new raw data.
+ */
+ void updateData(@Nullable List<PrintServiceInfo> services) {
+ if (services == null || services.isEmpty()) {
+ mServices = Collections.emptyList();
+ } else {
+ mServices = services;
+ }
+
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return 2;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ if (position == 0) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+ @Override
+ public int getCount() {
+ if (mServices.isEmpty()) {
+ return 0;
+ } else {
+ return mServices.size() + 1;
+ }
+ }
+
+ @Override
+ public Object getItem(int position) {
+ if (position == 0) {
+ return null;
+ } else {
+ return mServices.get(position - 1);
+ }
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return position != 0;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+ }
+
+ /**
+ * Adapter for the enabled services.
+ */
+ private class EnabledServicesAdapter extends PrintServiceInfoAdapter {
+ @Override
+ public void performAction(@IntRange(from = 0) int position) {
+ PrintServiceInfo service = (PrintServiceInfo) getItem(position);
+ String addPrinterActivityName = service.getAddPrintersActivityName();
+
+ if (!TextUtils.isEmpty(addPrinterActivityName)) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setComponent(new ComponentName(service.getComponentName().getPackageName(),
+ addPrinterActivityName));
+
+ try {
+ startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(LOG_TAG, "Cannot start add printers activity", e);
+ }
+ }
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (position == 0) {
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(R.layout.add_printer_list_header,
+ parent, false);
+ }
+
+ ((TextView) convertView.findViewById(R.id.text))
+ .setText(R.string.enabled_services_title);
+
+ return convertView;
+ }
+
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(R.layout.enabled_print_services_list_item,
+ parent, false);
+ }
+
+ PrintServiceInfo service = (PrintServiceInfo) getItem(position);
+
+ TextView title = (TextView) convertView.findViewById(R.id.title);
+ ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
+ TextView subtitle = (TextView) convertView.findViewById(R.id.subtitle);
+
+ title.setText(service.getResolveInfo().loadLabel(getPackageManager()));
+ icon.setImageDrawable(service.getResolveInfo().loadIcon(getPackageManager()));
+
+ if (TextUtils.isEmpty(service.getAddPrintersActivityName())) {
+ subtitle.setText(getString(R.string.cannot_add_printer));
+ } else {
+ subtitle.setText(getString(R.string.select_to_add_printers));
+ }
+
+ return convertView;
+ }
+ }
+
+ /**
+ * Adapter for the disabled services.
+ */
+ private class DisabledServicesAdapter extends PrintServiceInfoAdapter {
+ @Override
+ public void performAction(@IntRange(from = 0) int position) {
+ ((PrintManager) getSystemService(Context.PRINT_SERVICE)).setPrintServiceEnabled(
+ ((PrintServiceInfo) getItem(position)).getComponentName(), true);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (position == 0) {
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(R.layout.add_printer_list_header,
+ parent, false);
+ }
+
+ ((TextView) convertView.findViewById(R.id.text))
+ .setText(R.string.disabled_services_title);
+
+ return convertView;
+ }
+
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(
+ R.layout.disabled_print_services_list_item, parent, false);
+ }
+
+ PrintServiceInfo service = (PrintServiceInfo) getItem(position);
+
+ TextView title = (TextView) convertView.findViewById(R.id.title);
+ ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
+
+ title.setText(service.getResolveInfo().loadLabel(getPackageManager()));
+ icon.setImageDrawable(service.getResolveInfo().loadIcon(getPackageManager()));
+
+ return convertView;
+ }
+ }
+
+ /**
+ * Adapter for the recommended services.
+ */
+ private class RecommendedServicesAdapter extends ActionAdapter {
+ @Override
+ public int getCount() {
+ return 2;
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return 2;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ if (position == 0) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return null;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (position == 0) {
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(R.layout.add_printer_list_header,
+ parent, false);
+ }
+
+ ((TextView) convertView.findViewById(R.id.text))
+ .setText(R.string.recommended_services_title);
+
+ return convertView;
+ }
+
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(R.layout.all_print_services_list_item,
+ parent, false);
+ }
+
+ return convertView;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return position != 0;
+ }
+
+ @Override
+ public void performAction(@IntRange(from = 0) int position) {
+ String searchUri = Settings.Secure
+ .getString(getContentResolver(), Settings.Secure.PRINT_SERVICE_SEARCH_URI);
+
+ if (searchUri != null) {
+ try {
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri)));
+ } catch (ActivityNotFoundException e) {
+ Log.e(LOG_TAG, "Cannot start market", e);
+ }
+ }
+ }
+ }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
index 46a2098..3b5513a 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
@@ -16,7 +16,10 @@
package com.android.printspooler.ui;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.LoaderManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Loader;
@@ -28,9 +31,11 @@
import android.location.LocationRequest;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.print.PrintManager;
+import android.print.PrintServicesLoader;
import android.print.PrinterDiscoverySession;
import android.print.PrinterDiscoverySession.OnPrintersChangeListener;
import android.print.PrinterId;
@@ -127,11 +132,11 @@
}
}
- public FusedPrintersProvider(Context context) {
- super(context);
+ public FusedPrintersProvider(Activity activity, int internalLoaderId) {
+ super(activity);
mLocationLock = new Object();
- mPersistenceManager = new PersistenceManager(context);
- mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+ mPersistenceManager = new PersistenceManager(activity, internalLoaderId);
+ mLocationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
}
public void addHistoricalPrinter(PrinterInfo printer) {
@@ -383,7 +388,6 @@
mPrinters.clear();
if (mDiscoverySession != null) {
mDiscoverySession.destroy();
- mDiscoverySession = null;
}
}
@@ -499,7 +503,8 @@
updatePrinters(mDiscoverySession.getPrinters(), newFavoritePrinters, getCurrentLocation());
}
- private final class PersistenceManager {
+ private final class PersistenceManager implements
+ LoaderManager.LoaderCallbacks<List<PrintServiceInfo>> {
private static final String PERSIST_FILE_NAME = "printer_history.xml";
private static final String TAG_PRINTERS = "printers";
@@ -520,6 +525,15 @@
private final AtomicFile mStatePersistFile;
+ /**
+ * Whether the enabled print services have been updated since last time the history was
+ * read.
+ */
+ private boolean mAreEnabledServicesUpdated;
+
+ /** The enabled services read when they were last updated */
+ private @NonNull List<PrintServiceInfo> mEnabledServices;
+
private List<Pair<PrinterInfo, Location>> mHistoricalPrinters = new ArrayList<>();
private boolean mReadHistoryCompleted;
@@ -528,9 +542,52 @@
private volatile long mLastReadHistoryTimestamp;
- private PersistenceManager(Context context) {
- mStatePersistFile = new AtomicFile(new File(context.getFilesDir(),
+ private PersistenceManager(final Activity activity, final int internalLoaderId) {
+ mStatePersistFile = new AtomicFile(new File(activity.getFilesDir(),
PERSIST_FILE_NAME));
+
+ // Initialize enabled services to make sure they are set are the read task might be done
+ // before the loader updated the services the first time.
+ mEnabledServices = ((PrintManager) activity
+ .getSystemService(Context.PRINT_SERVICE))
+ .getPrintServices(PrintManager.ENABLED_SERVICES);
+
+ mAreEnabledServicesUpdated = true;
+
+ // Cannot start a loader while starting another, hence delay this loader
+ (new Handler(activity.getMainLooper())).post(new Runnable() {
+ @Override
+ public void run() {
+ activity.getLoaderManager().initLoader(internalLoaderId, null,
+ PersistenceManager.this);
+ }
+ });
+ }
+
+
+ @Override
+ public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) {
+ return new PrintServicesLoader(
+ (PrintManager) getContext().getSystemService(Context.PRINT_SERVICE),
+ getContext(), PrintManager.ENABLED_SERVICES);
+ }
+
+ @Override
+ public void onLoadFinished(Loader<List<PrintServiceInfo>> loader,
+ List<PrintServiceInfo> services) {
+ mAreEnabledServicesUpdated = true;
+ mEnabledServices = services;
+
+ // Ask the fused printer provider to reload which will cause the persistence manager to
+ // reload the history and reconsider the enabled services.
+ if (isStarted()) {
+ forceLoad();
+ }
+ }
+
+ @Override
+ public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
+ // no data is cached
}
public boolean isReadHistoryInProgress() {
@@ -644,7 +701,8 @@
}
public boolean isHistoryChanged() {
- return mLastReadHistoryTimestamp != mStatePersistFile.getBaseFile().lastModified();
+ return mAreEnabledServicesUpdated ||
+ mLastReadHistoryTimestamp != mStatePersistFile.getBaseFile().lastModified();
}
/**
@@ -738,19 +796,15 @@
}
// Ignore printer records whose target services are not enabled.
- PrintManager printManager = (PrintManager) getContext()
- .getSystemService(Context.PRINT_SERVICE);
- List<PrintServiceInfo> services = printManager
- .getEnabledPrintServices();
-
Set<ComponentName> enabledComponents = new ArraySet<>();
- final int installedServiceCount = services.size();
+ final int installedServiceCount = mEnabledServices.size();
for (int i = 0; i < installedServiceCount; i++) {
- ServiceInfo serviceInfo = services.get(i).getResolveInfo().serviceInfo;
+ ServiceInfo serviceInfo = mEnabledServices.get(i).getResolveInfo().serviceInfo;
ComponentName componentName = new ComponentName(
serviceInfo.packageName, serviceInfo.name);
enabledComponents.add(componentName);
}
+ mAreEnabledServicesUpdated = false;
final int printerCount = printers.size();
for (int i = printerCount - 1; i >= 0; i--) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 64f5cc6..ad4823e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -22,11 +22,13 @@
import android.app.DialogFragment;
import android.app.Fragment;
import android.app.FragmentTransaction;
+import android.app.LoaderManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.Loader;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
@@ -51,10 +53,12 @@
import android.print.PrintDocumentInfo;
import android.print.PrintJobInfo;
import android.print.PrintManager;
+import android.print.PrintServicesLoader;
import android.print.PrinterCapabilitiesInfo;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.printservice.PrintService;
+import android.printservice.PrintServiceInfo;
import android.provider.DocumentsContract;
import android.text.Editable;
import android.text.TextUtils;
@@ -94,7 +98,6 @@
import com.android.printspooler.util.MediaSizeUtils;
import com.android.printspooler.util.MediaSizeUtils.MediaSizeComparator;
import com.android.printspooler.util.PageRangeUtils;
-import com.android.printspooler.util.PrintOptionUtils;
import com.android.printspooler.widget.PrintContentView;
import com.android.printspooler.widget.PrintContentView.OptionsStateChangeListener;
import com.android.printspooler.widget.PrintContentView.OptionsStateController;
@@ -113,12 +116,14 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PrintActivity extends Activity implements RemotePrintDocument.UpdateResultCallbacks,
PrintErrorFragment.OnActionListener, PageAdapter.ContentCallbacks,
- OptionsStateChangeListener, OptionsStateController {
+ OptionsStateChangeListener, OptionsStateController,
+ LoaderManager.LoaderCallbacks<List<PrintServiceInfo>> {
private static final String LOG_TAG = "PrintActivity";
private static final boolean DEBUG = false;
@@ -129,6 +134,10 @@
private static final String HAS_PRINTED_PREF = "has_printed";
+ private static final int LOADER_ID_ENABLED_PRINT_SERVICES = 1;
+ private static final int LOADER_ID_PRINT_REGISTRY = 2;
+ private static final int LOADER_ID_PRINT_REGISTRY_INT = 3;
+
private static final int ORIENTATION_PORTRAIT = 0;
private static final int ORIENTATION_LANDSCAPE = 1;
@@ -139,7 +148,7 @@
private static final int DEST_ADAPTER_MAX_ITEM_COUNT = 9;
private static final int DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF = Integer.MAX_VALUE;
- private static final int DEST_ADAPTER_ITEM_ID_ALL_PRINTERS = Integer.MAX_VALUE - 1;
+ private static final int DEST_ADAPTER_ITEM_ID_MORE = Integer.MAX_VALUE - 1;
private static final int STATE_INITIALIZING = 0;
private static final int STATE_CONFIGURING = 1;
@@ -236,6 +245,15 @@
private int mUiState = UI_STATE_PREVIEW;
+ /** Observer for changes to the printers */
+ private PrintersObserver mPrintersObserver;
+
+ /** Advances options activity name for current printer */
+ private ComponentName mAdvancedPrintOptionsActivity;
+
+ /** Whether at least one print services is enabled or not */
+ private boolean mArePrintServicesEnabled;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -275,6 +293,8 @@
}
}
});
+
+ getLoaderManager().initLoader(LOADER_ID_ENABLED_PRINT_SERVICES, null, this);
}
private void onConnectedToPrintSpooler(final IBinder documentAdapter) {
@@ -289,7 +309,7 @@
public void run() {
onPrinterRegistryReady(documentAdapter);
}
- });
+ }, LOADER_ID_PRINT_REGISTRY, LOADER_ID_PRINT_REGISTRY_INT);
}
private void onPrinterRegistryReady(IBinder documentAdapter) {
@@ -713,15 +733,12 @@
}
private void startAdvancedPrintOptionsActivity(PrinterInfo printer) {
- ComponentName serviceName = printer.getId().getServiceName();
-
- String activityName = PrintOptionUtils.getAdvancedOptionsActivityName(this, serviceName);
- if (TextUtils.isEmpty(activityName)) {
+ if (mAdvancedPrintOptionsActivity == null) {
return;
}
Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.setComponent(new ComponentName(serviceName.getPackageName(), activityName));
+ intent.setComponent(mAdvancedPrintOptionsActivity);
List<ResolveInfo> resolvedActivities = getPackageManager()
.queryIntentActivities(intent, 0);
@@ -731,7 +748,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 +779,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 +795,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++) {
@@ -1184,7 +1208,8 @@
mCopiesEditText.addTextChangedListener(new EditTextWatcher());
// Destination.
- mDestinationSpinnerAdapter.registerDataSetObserver(new PrintersObserver());
+ mPrintersObserver = new PrintersObserver();
+ mDestinationSpinnerAdapter.registerDataSetObserver(mPrintersObserver);
mDestinationSpinner = (Spinner) findViewById(R.id.destination_spinner);
mDestinationSpinner.setAdapter(mDestinationSpinnerAdapter);
mDestinationSpinner.setOnItemSelectedListener(itemSelectedListener);
@@ -1272,6 +1297,59 @@
}
}
+ @Override
+ public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) {
+ return new PrintServicesLoader((PrintManager) getSystemService(Context.PRINT_SERVICE), this,
+ PrintManager.ENABLED_SERVICES);
+ }
+
+ @Override
+ public void onLoadFinished(Loader<List<PrintServiceInfo>> loader,
+ List<PrintServiceInfo> services) {
+ ComponentName newAdvancedPrintOptionsActivity = null;
+ if (mCurrentPrinter != null && services != null) {
+ final int numServices = services.size();
+ for (int i = 0; i < numServices; i++) {
+ PrintServiceInfo service = services.get(i);
+
+ if (service.getComponentName().equals(mCurrentPrinter.getId().getServiceName())) {
+ String advancedOptionsActivityName = service.getAdvancedOptionsActivityName();
+
+ if (!TextUtils.isEmpty(advancedOptionsActivityName)) {
+ newAdvancedPrintOptionsActivity = new ComponentName(
+ service.getComponentName().getPackageName(),
+ advancedOptionsActivityName);
+
+ break;
+ }
+ }
+ }
+ }
+
+ if (!Objects.equals(newAdvancedPrintOptionsActivity, mAdvancedPrintOptionsActivity)) {
+ mAdvancedPrintOptionsActivity = newAdvancedPrintOptionsActivity;
+ updateOptionsUi();
+ }
+
+ boolean newArePrintServicesEnabled = services != null && !services.isEmpty();
+ if (mArePrintServicesEnabled != newArePrintServicesEnabled) {
+ mArePrintServicesEnabled = newArePrintServicesEnabled;
+
+ // Reload mDestinationSpinnerAdapter as mArePrintServicesEnabled changed and the adapter
+ // reads that in DestinationAdapter#getMoreItemTitle
+ if (mDestinationSpinnerAdapter != null) {
+ mDestinationSpinnerAdapter.notifyDataSetChanged();
+ }
+ }
+ }
+
+ @Override
+ public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
+ if (!isFinishing()) {
+ onLoadFinished(loader, null);
+ }
+ }
+
/**
* A dialog that asks the user to approve a {@link PrintService}. This dialog is automatically
* dismissed if the same {@link PrintService} gets approved by another
@@ -1711,9 +1789,7 @@
}
// Advanced print options
- ComponentName serviceName = mCurrentPrinter.getId().getServiceName();
- if (!TextUtils.isEmpty(PrintOptionUtils.getAdvancedOptionsActivityName(
- this, serviceName))) {
+ if (mAdvancedPrintOptionsActivity != null) {
mMoreOptionsButton.setVisibility(View.VISIBLE);
mMoreOptionsButton.setEnabled(true);
} else {
@@ -1962,6 +2038,10 @@
mPrinterRegistry.setTrackedPrinter(null);
}
+ if (mPrintersObserver != null) {
+ mDestinationSpinnerAdapter.unregisterDataSetObserver(mPrintersObserver);
+ }
+
if (mState != STATE_INITIALIZING) {
mProgressMessageController.cancel();
mSpoolerProvider.destroy();
@@ -2201,14 +2281,14 @@
if (position == 0) {
return DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF;
} else if (position == 1) {
- return DEST_ADAPTER_ITEM_ID_ALL_PRINTERS;
+ return DEST_ADAPTER_ITEM_ID_MORE;
}
} else {
if (position == 1) {
return DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF;
}
if (position == getCount() - 1) {
- return DEST_ADAPTER_ITEM_ID_ALL_PRINTERS;
+ return DEST_ADAPTER_ITEM_ID_MORE;
}
}
return position;
@@ -2221,6 +2301,14 @@
return view;
}
+ private String getMoreItemTitle() {
+ if (mArePrintServicesEnabled) {
+ return getString(R.string.all_printers);
+ } else {
+ return getString(R.string.print_add_printer);
+ }
+ }
+
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (mShowDestinationPrompt) {
@@ -2249,7 +2337,7 @@
title = printerHolder.printer.getName();
icon = getResources().getDrawable(R.drawable.ic_menu_savetopdf, null);
} else if (position == 1) {
- title = getString(R.string.all_printers);
+ title = getMoreItemTitle();
}
} else {
if (position == 1 && getPdfPrinter() != null) {
@@ -2257,7 +2345,7 @@
title = printerHolder.printer.getName();
icon = getResources().getDrawable(R.drawable.ic_menu_savetopdf, null);
} else if (position == getCount() - 1) {
- title = getString(R.string.all_printers);
+ title = getMoreItemTitle();
} else {
PrinterHolder printerHolder = (PrinterHolder) getItem(position);
PrinterInfo printInfo = printerHolder.printer;
@@ -2292,7 +2380,7 @@
}
iconView.setImageDrawable(icon);
} else {
- iconView.setVisibility(View.GONE);
+ iconView.setVisibility(View.INVISIBLE);
}
return convertView;
@@ -2337,6 +2425,7 @@
PrinterInfo updatedPrinter = newPrintersMap.remove(oldPrinterId);
if (updatedPrinter != null) {
printerHolder.printer = updatedPrinter;
+ printerHolder.removed = false;
} else {
printerHolder.removed = true;
}
@@ -2442,6 +2531,7 @@
PrinterCapabilitiesInfo oldCapab = oldPrinterState.getCapabilities();
PrinterCapabilitiesInfo newCapab = newPrinterState.getCapabilities();
+ final boolean hadCabab = oldCapab != null;
final boolean hasCapab = newCapab != null;
final boolean gotCapab = oldCapab == null && newCapab != null;
final boolean lostCapab = oldCapab != null && newCapab == null;
@@ -2460,23 +2550,31 @@
mCurrentPrinter = newPrinterState;
- if ((isActive && gotCapab) || (becameActive && hasCapab)) {
- if (hasCapab && capabChanged) {
- updatePrintAttributesFromCapabilities(newCapab);
- updatePrintPreviewController(false);
- }
- onPrinterAvailable(newPrinterState);
- } else if ((becameInactive && hasCapab) || (isActive && lostCapab)) {
- onPrinterUnavailable(newPrinterState);
- }
-
final boolean updateNeeded = ((capabChanged && hasCapab && isActive)
|| (becameActive && hasCapab) || (isActive && gotCapab));
+ if (capabChanged && hasCapab) {
+ updatePrintAttributesFromCapabilities(newCapab);
+ }
+
+ if (updateNeeded) {
+ updatePrintPreviewController(false);
+ }
+
+ if ((isActive && gotCapab) || (becameActive && hasCapab)) {
+ onPrinterAvailable(newPrinterState);
+ } else if ((becameInactive && hadCabab) || (isActive && lostCapab)) {
+ onPrinterUnavailable(newPrinterState);
+ }
+
if (updateNeeded && canUpdateDocument()) {
updateDocument(false);
}
+ // Force a reload of the enabled print services to update mAdvancedPrintOptionsActivity
+ // in onLoadFinished();
+ getLoaderManager().getLoader(LOADER_ID_ENABLED_PRINT_SERVICES).forceLoad();
+
updateOptionsUi();
updateSummary();
}
@@ -2502,7 +2600,7 @@
return;
}
- if (id == DEST_ADAPTER_ITEM_ID_ALL_PRINTERS) {
+ if (id == DEST_ADAPTER_ITEM_ID_MORE) {
startSelectPrinterActivity();
return;
}
@@ -2536,6 +2634,10 @@
}
mPrinterAvailabilityDetector.updatePrinter(currentPrinter);
+
+ // Force a reload of the enabled print services to update
+ // mAdvancedPrintOptionsActivity in onLoadFinished();
+ getLoaderManager().getLoader(LOADER_ID_ENABLED_PRINT_SERVICES).forceLoad();
} else if (spinner == mMediaSizeSpinner) {
SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(position);
PrintAttributes attributes = mPrintJob.getAttributes();
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
index 6d60bb8..86366dd 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
@@ -33,7 +33,7 @@
public class PrinterRegistry {
- private static final int LOADER_ID_PRINTERS_LOADER = 1;
+ private final int mLoaderId;
private final Activity mActivity;
@@ -52,12 +52,17 @@
public void onPrintersInvalid();
}
- public PrinterRegistry(Activity activity, Runnable readyCallback) {
+ public PrinterRegistry(Activity activity, Runnable readyCallback, int loaderId,
+ int internalLoaderId) {
+ mLoaderId = loaderId;
mActivity = activity;
mReadyCallback = readyCallback;
mHandler = new MyHandler(activity.getMainLooper());
- activity.getLoaderManager().initLoader(LOADER_ID_PRINTERS_LOADER,
- null, mLoaderCallbacks);
+
+ Bundle loaderData = new Bundle(1);
+ loaderData.putInt(null, internalLoaderId);
+
+ activity.getLoaderManager().initLoader(loaderId, loaderData, mLoaderCallbacks);
}
public void setOnPrintersChangeListener(OnPrintersChangeListener listener) {
@@ -106,7 +111,7 @@
}
private FusedPrintersProvider getPrinterProvider() {
- Loader<?> loader = mActivity.getLoaderManager().getLoader(LOADER_ID_PRINTERS_LOADER);
+ Loader<?> loader = mActivity.getLoaderManager().getLoader(mLoaderId);
return (FusedPrintersProvider) loader;
}
@@ -114,38 +119,34 @@
new LoaderCallbacks<List<PrinterInfo>>() {
@Override
public void onLoaderReset(Loader<List<PrinterInfo>> loader) {
- if (loader.getId() == LOADER_ID_PRINTERS_LOADER) {
- mPrinters.clear();
- if (mOnPrintersChangeListener != null) {
- // Post a message as we are in onLoadFinished and certain operations
- // are not allowed in this callback, such as fragment transactions.
- // Clients should not handle this explicitly.
- mHandler.obtainMessage(MyHandler.MSG_PRINTERS_INVALID,
- mOnPrintersChangeListener).sendToTarget();
- }
+ mPrinters.clear();
+ if (mOnPrintersChangeListener != null) {
+ // Post a message as we are in onLoadFinished and certain operations
+ // are not allowed in this callback, such as fragment transactions.
+ // Clients should not handle this explicitly.
+ mHandler.obtainMessage(MyHandler.MSG_PRINTERS_INVALID,
+ mOnPrintersChangeListener).sendToTarget();
}
}
// LoaderCallbacks#onLoadFinished
@Override
public void onLoadFinished(Loader<List<PrinterInfo>> loader, List<PrinterInfo> printers) {
- if (loader.getId() == LOADER_ID_PRINTERS_LOADER) {
- mPrinters.clear();
- mPrinters.addAll(printers);
- if (mOnPrintersChangeListener != null) {
- // Post a message as we are in onLoadFinished and certain operations
- // are not allowed in this callback, such as fragment transactions.
- // Clients should not handle this explicitly.
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = mOnPrintersChangeListener;
- args.arg2 = printers;
- mHandler.obtainMessage(MyHandler.MSG_PRINTERS_CHANGED, args).sendToTarget();
- }
- if (!mReady) {
- mReady = true;
- if (mReadyCallback != null) {
- mReadyCallback.run();
- }
+ mPrinters.clear();
+ mPrinters.addAll(printers);
+ if (mOnPrintersChangeListener != null) {
+ // Post a message as we are in onLoadFinished and certain operations
+ // are not allowed in this callback, such as fragment transactions.
+ // Clients should not handle this explicitly.
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = mOnPrintersChangeListener;
+ args.arg2 = printers;
+ mHandler.obtainMessage(MyHandler.MSG_PRINTERS_CHANGED, args).sendToTarget();
+ }
+ if (!mReady) {
+ mReady = true;
+ if (mReadyCallback != null) {
+ mReadyCallback.run();
}
}
}
@@ -153,10 +154,7 @@
// LoaderCallbacks#onCreateLoader
@Override
public Loader<List<PrinterInfo>> onCreateLoader(int id, Bundle args) {
- if (id == LOADER_ID_PRINTERS_LOADER) {
- return new FusedPrintersProvider(mActivity);
- }
- return null;
+ return new FusedPrintersProvider(mActivity, args.getInt(null));
}
};
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
index 4f7624a..e53a522 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
@@ -17,31 +17,18 @@
package com.android.printspooler.ui;
import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.Fragment;
-import android.app.FragmentTransaction;
-import android.content.ActivityNotFoundException;
-import android.content.ComponentName;
+import android.app.LoaderManager;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
-import android.content.pm.ActivityInfo;
+import android.content.Loader;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.database.ContentObserver;
import android.database.DataSetObserver;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
import android.print.PrintManager;
+import android.print.PrintServicesLoader;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.printservice.PrintServiceInfo;
@@ -59,17 +46,16 @@
import android.view.accessibility.AccessibilityManager;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.TextView;
import android.widget.Toast;
-import com.android.internal.content.PackageMonitor;
import com.android.printspooler.R;
import java.util.ArrayList;
@@ -78,35 +64,33 @@
/**
* This is an activity for selecting a printer.
*/
-public final class SelectPrinterActivity extends Activity {
+public final class SelectPrinterActivity extends Activity implements
+ LoaderManager.LoaderCallbacks<List<PrintServiceInfo>> {
private static final String LOG_TAG = "SelectPrinterFragment";
+ private static final int LOADER_ID_PRINT_REGISTRY = 1;
+ private static final int LOADER_ID_PRINT_REGISTRY_INT = 2;
+ private static final int LOADER_ID_ENABLED_PRINT_SERVICES = 3;
+
public static final String INTENT_EXTRA_PRINTER_ID = "INTENT_EXTRA_PRINTER_ID";
- private static final String FRAGMENT_TAG_ADD_PRINTER_DIALOG =
- "FRAGMENT_TAG_ADD_PRINTER_DIALOG";
-
- private static final String FRAGMENT_ARGUMENT_PRINT_SERVICE_INFOS =
- "FRAGMENT_ARGUMENT_PRINT_SERVICE_INFOS";
-
private static final String EXTRA_PRINTER_ID = "EXTRA_PRINTER_ID";
+ private static final String KEY_NOT_FIRST_CREATE = "KEY_NOT_FIRST_CREATE";
+
/** If there are any enabled print services */
private boolean mHasEnabledPrintServices;
- private final ArrayList<PrintServiceInfo> mAddPrinterServices =
- new ArrayList<>();
-
private PrinterRegistry mPrinterRegistry;
private ListView mListView;
private AnnounceFilterResult mAnnounceFilterResult;
- /** Monitor if new print services get enabled or disabled */
- private ContentObserver mPrintServicesDisabledObserver;
- private PackageMonitor mPackageObserver;
+ private void startAddPrinterActivity() {
+ startActivity(new Intent(this, AddPrinterActivity.class));
+ }
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -115,7 +99,8 @@
setContentView(R.layout.select_printer_activity);
- mPrinterRegistry = new PrinterRegistry(this, null);
+ mPrinterRegistry = new PrinterRegistry(this, null, LOADER_ID_PRINT_REGISTRY,
+ LOADER_ID_PRINT_REGISTRY_INT);
// Hook up the list view.
mListView = (ListView) findViewById(android.R.id.list);
@@ -145,22 +130,67 @@
}
PrinterInfo printer = (PrinterInfo) mListView.getAdapter().getItem(position);
- onPrinterSelected(printer.getId());
+
+ if (printer == null) {
+ startAddPrinterActivity();
+ } else {
+ onPrinterSelected(printer.getId());
+ }
+ }
+ });
+
+ findViewById(R.id.button).setOnClickListener(new OnClickListener() {
+ @Override public void onClick(View v) {
+ startAddPrinterActivity();
}
});
registerForContextMenu(mListView);
- // Display a notification about disabled services if there are disabled services
- String disabledServicesSetting = Settings.Secure.getString(getContentResolver(),
- Settings.Secure.DISABLED_PRINT_SERVICES);
- if (!TextUtils.isEmpty(disabledServicesSetting)) {
- Toast.makeText(this, getString(R.string.print_services_disabled_toast),
- Toast.LENGTH_LONG).show();
+ getLoaderManager().initLoader(LOADER_ID_ENABLED_PRINT_SERVICES, null, this);
+
+ // On first creation:
+ //
+ // If no services are installed, instantly open add printer dialog.
+ // If some are disabled and some are enabled show a toast to notify the user
+ if (savedInstanceState == null || !savedInstanceState.getBoolean(KEY_NOT_FIRST_CREATE)) {
+ List<PrintServiceInfo> allServices =
+ ((PrintManager) getSystemService(Context.PRINT_SERVICE))
+ .getPrintServices(PrintManager.ALL_SERVICES);
+ boolean hasEnabledServices = false;
+ boolean hasDisabledServices = false;
+
+ if (allServices != null) {
+ final int numServices = allServices.size();
+ for (int i = 0; i < numServices; i++) {
+ if (allServices.get(i).isEnabled()) {
+ hasEnabledServices = true;
+ } else {
+ hasDisabledServices = true;
+ }
+ }
+ }
+
+ if (!hasEnabledServices) {
+ startAddPrinterActivity();
+ } else if (hasDisabledServices) {
+ String disabledServicesSetting = Settings.Secure.getString(getContentResolver(),
+ Settings.Secure.DISABLED_PRINT_SERVICES);
+ if (!TextUtils.isEmpty(disabledServicesSetting)) {
+ Toast.makeText(this, getString(R.string.print_services_disabled_toast),
+ Toast.LENGTH_LONG).show();
+ }
+ }
}
}
@Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(KEY_NOT_FIRST_CREATE, true);
+ }
+
+ @Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
@@ -249,60 +279,13 @@
* Adjust the UI if the enabled print services changed.
*/
private synchronized void onPrintServicesUpdate() {
- updateServicesWithAddPrinterActivity();
updateEmptyView((DestinationAdapter)mListView.getAdapter());
invalidateOptionsMenu();
}
- /**
- * Register listener for changes to the enabled print services.
- */
- private void registerServiceMonitor() {
- // Listen for services getting disabled
- mPrintServicesDisabledObserver = new ContentObserver(new Handler()) {
- @Override
- public void onChange(boolean selfChange) {
- onPrintServicesUpdate();
- }
- };
-
- // Listen for services getting installed or uninstalled
- mPackageObserver = new PackageMonitor() {
- @Override
- public void onPackageModified(String packageName) {
- onPrintServicesUpdate();
- }
-
- @Override
- public void onPackageRemoved(String packageName, int uid) {
- onPrintServicesUpdate();
- }
-
- @Override
- public void onPackageAdded(String packageName, int uid) {
- onPrintServicesUpdate();
- }
- };
-
- getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.DISABLED_PRINT_SERVICES), false,
- mPrintServicesDisabledObserver);
-
- mPackageObserver.register(this, getMainLooper(), false);
- }
-
- /**
- * Unregister the listeners for changes to the enabled print services.
- */
- private void unregisterServiceMonitorIfNeeded() {
- getContentResolver().unregisterContentObserver(mPrintServicesDisabledObserver);
- mPackageObserver.unregister();
- }
-
@Override
public void onStart() {
super.onStart();
- registerServiceMonitor();
onPrintServicesUpdate();
}
@@ -316,19 +299,9 @@
@Override
public void onStop() {
- unregisterServiceMonitorIfNeeded();
super.onStop();
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == R.id.action_add_printer) {
- showAddPrinterSelectionDialog();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
private void onPrinterSelected(PrinterId printerId) {
Intent intent = new Intent();
intent.putExtra(INTENT_EXTRA_PRINTER_ID, printerId);
@@ -336,68 +309,6 @@
finish();
}
- private void updateServicesWithAddPrinterActivity() {
- mHasEnabledPrintServices = true;
- mAddPrinterServices.clear();
-
- // Get all enabled print services.
- PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE);
- List<PrintServiceInfo> enabledServices = printManager.getEnabledPrintServices();
-
- // No enabled print services - done.
- if (enabledServices.isEmpty()) {
- mHasEnabledPrintServices = false;
- return;
- }
-
- // Find the services with valid add printers activities.
- final int enabledServiceCount = enabledServices.size();
- for (int i = 0; i < enabledServiceCount; i++) {
- PrintServiceInfo enabledService = enabledServices.get(i);
-
- // No add printers activity declared - next.
- if (TextUtils.isEmpty(enabledService.getAddPrintersActivityName())) {
- continue;
- }
-
- ServiceInfo serviceInfo = enabledService.getResolveInfo().serviceInfo;
- ComponentName addPrintersComponentName = new ComponentName(
- serviceInfo.packageName, enabledService.getAddPrintersActivityName());
- Intent addPritnersIntent = new Intent()
- .setComponent(addPrintersComponentName);
-
- // The add printers activity is valid - add it.
- PackageManager pm = getPackageManager();
- List<ResolveInfo> resolvedActivities = pm.queryIntentActivities(addPritnersIntent, 0);
- if (!resolvedActivities.isEmpty()) {
- // The activity is a component name, therefore it is one or none.
- ActivityInfo activityInfo = resolvedActivities.get(0).activityInfo;
- if (activityInfo.exported
- && (activityInfo.permission == null
- || pm.checkPermission(activityInfo.permission, getPackageName())
- == PackageManager.PERMISSION_GRANTED)) {
- mAddPrinterServices.add(enabledService);
- }
- }
- }
- }
-
- private void showAddPrinterSelectionDialog() {
- FragmentTransaction transaction = getFragmentManager().beginTransaction();
- Fragment oldFragment = getFragmentManager().findFragmentByTag(
- FRAGMENT_TAG_ADD_PRINTER_DIALOG);
- if (oldFragment != null) {
- transaction.remove(oldFragment);
- }
- AddPrinterAlertDialogFragment newFragment = new AddPrinterAlertDialogFragment();
- Bundle arguments = new Bundle();
- arguments.putParcelableArrayList(FRAGMENT_ARGUMENT_PRINT_SERVICE_INFOS,
- mAddPrinterServices);
- newFragment.setArguments(arguments);
- transaction.add(newFragment, FRAGMENT_TAG_ADD_PRINTER_DIALOG);
- transaction.commit();
- }
-
public void updateEmptyView(DestinationAdapter adapter) {
if (mListView.getEmptyView() == null) {
View emptyView = findViewById(R.id.empty_print_state);
@@ -426,71 +337,28 @@
}
}
- public static class AddPrinterAlertDialogFragment extends DialogFragment {
+ @Override
+ public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) {
+ return new PrintServicesLoader((PrintManager) getSystemService(Context.PRINT_SERVICE), this,
+ PrintManager.ENABLED_SERVICES);
+ }
- private String mAddPrintServiceItem;
+ @Override
+ public void onLoadFinished(Loader<List<PrintServiceInfo>> loader,
+ List<PrintServiceInfo> data) {
+ if (data == null || data.isEmpty()) {
+ mHasEnabledPrintServices = false;
+ } else {
+ mHasEnabledPrintServices = true;
+ }
- @Override
- @SuppressWarnings("unchecked")
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
- .setTitle(R.string.choose_print_service);
+ onPrintServicesUpdate();
+ }
- final List<PrintServiceInfo> printServices = (List<PrintServiceInfo>) (List<?>)
- getArguments().getParcelableArrayList(FRAGMENT_ARGUMENT_PRINT_SERVICE_INFOS);
-
- final ArrayAdapter<String> adapter = new ArrayAdapter<>(
- getActivity(), android.R.layout.simple_list_item_1);
- final int printServiceCount = printServices.size();
- for (int i = 0; i < printServiceCount; i++) {
- PrintServiceInfo printService = printServices.get(i);
- adapter.add(printService.getResolveInfo().loadLabel(
- getActivity().getPackageManager()).toString());
- }
-
- final String searchUri = Settings.Secure.getString(getActivity().getContentResolver(),
- Settings.Secure.PRINT_SERVICE_SEARCH_URI);
- final Intent viewIntent;
- if (!TextUtils.isEmpty(searchUri)) {
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri));
- if (getActivity().getPackageManager().resolveActivity(intent, 0) != null) {
- viewIntent = intent;
- mAddPrintServiceItem = getString(R.string.add_print_service_label);
- adapter.add(mAddPrintServiceItem);
- } else {
- viewIntent = null;
- }
- } else {
- viewIntent = null;
- }
-
- builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- String item = adapter.getItem(which);
- if (item.equals(mAddPrintServiceItem)) {
- try {
- startActivity(viewIntent);
- } catch (ActivityNotFoundException anfe) {
- Log.w(LOG_TAG, "Couldn't start add printer activity", anfe);
- }
- } else {
- PrintServiceInfo printService = printServices.get(which);
- ComponentName componentName = new ComponentName(
- printService.getResolveInfo().serviceInfo.packageName,
- printService.getAddPrintersActivityName());
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.setComponent(componentName);
- try {
- startActivity(intent);
- } catch (ActivityNotFoundException anfe) {
- Log.w(LOG_TAG, "Couldn't start add printer activity", anfe);
- }
- }
- }
- });
-
- return builder.create();
+ @Override
+ public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
+ if (!isFinishing()) {
+ onLoadFinished(loader, null);
}
}
@@ -592,14 +460,40 @@
@Override
public int getCount() {
synchronized (mLock) {
- return mFilteredPrinters.size();
+ if (mFilteredPrinters.isEmpty()) {
+ return 0;
+ } else {
+ // Add "add printer" item to the end of the list. If the list is empty there is
+ // a link on the empty view
+ return mFilteredPrinters.size() + 1;
+ }
+ }
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return 2;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ // Use separate view types for the "add printer" item an the items referring to printers
+ if (getItem(position) == null) {
+ return 0;
+ } else {
+ return 1;
}
}
@Override
public Object getItem(int position) {
synchronized (mLock) {
- return mFilteredPrinters.get(position);
+ if (position < mFilteredPrinters.size()) {
+ return mFilteredPrinters.get(position);
+ } else {
+ // Return null to mark this as the "add printer item"
+ return null;
+ }
}
}
@@ -615,6 +509,18 @@
@Override
public View getView(int position, View convertView, ViewGroup parent) {
+ final PrinterInfo printer = (PrinterInfo) getItem(position);
+
+ // Handle "add printer item"
+ if (printer == null) {
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(R.layout.add_printer_list_item,
+ parent, false);
+ }
+
+ return convertView;
+ }
+
if (convertView == null) {
convertView = getLayoutInflater().inflate(
R.layout.printer_list_item, parent, false);
@@ -622,7 +528,6 @@
convertView.setEnabled(isActionable(position));
- final PrinterInfo printer = (PrinterInfo) getItem(position);
CharSequence title = printer.getName();
Drawable icon = printer.loadIcon(SelectPrinterActivity.this);
@@ -661,7 +566,7 @@
subtitleView.setVisibility(View.GONE);
}
- ImageView moreInfoView = (ImageView) convertView.findViewById(R.id.more_info);
+ LinearLayout moreInfoView = (LinearLayout) convertView.findViewById(R.id.more_info);
if (printer.getInfoIntent() != null) {
moreInfoView.setVisibility(View.VISIBLE);
moreInfoView.setOnClickListener(new OnClickListener() {
@@ -699,7 +604,12 @@
public boolean isActionable(int position) {
PrinterInfo printer = (PrinterInfo) getItem(position);
- return printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE;
+
+ if (printer == null) {
+ return true;
+ } else {
+ return printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE;
+ }
}
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/util/PrintOptionUtils.java b/packages/PrintSpooler/src/com/android/printspooler/util/PrintOptionUtils.java
deleted file mode 100644
index 446952d..0000000
--- a/packages/PrintSpooler/src/com/android/printspooler/util/PrintOptionUtils.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.printspooler.util;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.ServiceInfo;
-import android.print.PrintManager;
-import android.printservice.PrintServiceInfo;
-
-import java.util.List;
-
-public class PrintOptionUtils {
-
- private PrintOptionUtils() {
- /* ignore - hide constructor */
- }
-
- /**
- * Gets the advanced options activity name for a print service.
- *
- * @param context Context for accessing system resources.
- * @param serviceName The print service name.
- * @return The advanced options activity name or null.
- */
- public static String getAdvancedOptionsActivityName(Context context,
- ComponentName serviceName) {
- PrintManager printManager = (PrintManager) context.getSystemService(
- Context.PRINT_SERVICE);
- List<PrintServiceInfo> printServices = printManager.getEnabledPrintServices();
- final int printServiceCount = printServices.size();
- for (int i = 0; i < printServiceCount; i ++) {
- PrintServiceInfo printServiceInfo = printServices.get(i);
- ServiceInfo serviceInfo = printServiceInfo.getResolveInfo().serviceInfo;
- if (serviceInfo.name.equals(serviceName.getClassName())
- && serviceInfo.packageName.equals(serviceName.getPackageName())) {
- return printServiceInfo.getAdvancedOptionsActivityName();
- }
- }
- return null;
- }
-}
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/layout/settings_with_drawer.xml b/packages/SettingsLib/res/layout/settings_with_drawer.xml
index 9e5d029..67296a6 100644
--- a/packages/SettingsLib/res/layout/settings_with_drawer.xml
+++ b/packages/SettingsLib/res/layout/settings_with_drawer.xml
@@ -17,14 +17,15 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:background="?android:attr/colorPrimaryDark">
<!-- The main content view -->
<LinearLayout
android:id="@+id/content_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:fitsSystemWindows="false" >
+ android:fitsSystemWindows="true" >
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -36,14 +37,14 @@
android:layout_height="wrap_content"
android:navigationContentDescription="@*android:string/action_bar_up_description"
android:theme="?android:attr/actionBarTheme"
- android:paddingTop="@*android:dimen/status_bar_height"
style="?android:attr/toolbarStyle"
android:background="?android:attr/colorPrimary" />
</FrameLayout>
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
- android:layout_height="fill_parent" />
+ android:layout_height="fill_parent"
+ android:background="?android:attr/windowBackground" />
</LinearLayout>
<!-- The navigation drawer -->
<ListView android:id="@+id/left_drawer"
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 94e376c8..a408c08 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Laai nie"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Vol"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Beheer deur administrateur"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Geaktiveer deur administrateur"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Gedeaktiveer deur administrateur"</string>
<string name="home" msgid="8263346537524314127">"Tuis"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> gelede"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> oor"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index c605d2d..7ae97e2 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ኃይል እየሞላ አይደለም"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ሙሉነው"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"በአስተዳዳሪ ቁጥጥር የተደረገበት"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"በአስተዳዳሪ የነቃ"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"በአስተዳዳሪ የተሰናከለ"</string>
<string name="home" msgid="8263346537524314127">"መነሻ"</string>
<string name="charge_length_format" msgid="8978516217024434156">"ከ<xliff:g id="ID_1">%1$s</xliff:g> በፊት"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ቀርቷል"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 975051a..eb76e1f 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"لا يتم الشحن"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ممتلئة"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"إعدادات يتحكم فيها المشرف"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"تم التمكين بواسطة المشرف"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"تم التعطيل بواسطة المشرف"</string>
<string name="home" msgid="8263346537524314127">"الشاشة الرئيسية"</string>
<string name="charge_length_format" msgid="8978516217024434156">"قبل <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"يتبقى <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
index 3f78fa2..9903397 100644
--- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Enerji doldurulmur"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Tam"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Admin tərəfindən nəzarət olunur"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Administrator tərəfindən aktiv edildi"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Administrator tərəfindən deaktiv edildi"</string>
<string name="home" msgid="8263346537524314127">"Əsas səhifə"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> əvvəl"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> qalıb"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index a38542d..f570d09 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ne puni se"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Puno"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontroliše administrator"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Omogućio je administrator"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Onemogućio je administrator"</string>
<string name="home" msgid="8263346537524314127">"Početni"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Pre <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Još <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index e3c8d8a..72652c9 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не се зарежда"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Пълна"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролира се от администратор"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Активирано от администратора"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Деактивирано от администратора"</string>
<string name="home" msgid="8263346537524314127">"Начало"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Преди <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Оставащо време: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml
index d3c9e6b..b863773 100644
--- a/packages/SettingsLib/res/values-bn-rBD/strings.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"চার্জ হচ্ছে না"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"পূর্ণ"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"প্রশাসকের দ্বারা নিয়ন্ত্রিত"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"প্রশাসক সক্ষম করেছেন"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"প্রশাসক অক্ষম করেছেন"</string>
<string name="home" msgid="8263346537524314127">"হোম"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> আগে"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> বাকী আছে"</string>
diff --git a/packages/SettingsLib/res/values-bs-rBA/strings.xml b/packages/SettingsLib/res/values-bs-rBA/strings.xml
index 673b08b..542c3ce 100644
--- a/packages/SettingsLib/res/values-bs-rBA/strings.xml
+++ b/packages/SettingsLib/res/values-bs-rBA/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ne puni se"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Puna"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Pod kontrolom administratora"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Omogućio administrator"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Onemogućio je administrator"</string>
<string name="home" msgid="8263346537524314127">"Početna stranica"</string>
<string name="charge_length_format" msgid="8978516217024434156">"prije <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Još otprilike <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index d4d2f6c..e2c4495 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"No s\'està carregant"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Plena"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlat per l\'administrador"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Opció activada per l\'administrador"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Opció desactivada per l\'administrador"</string>
<string name="home" msgid="8263346537524314127">"Inici"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Fa <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Temps restant: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 00d4f47..f713ceb 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nenabíjí se"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Nabitá"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Spravováno administrátorem"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Povoleno administrátorem"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Zakázáno administrátorem"</string>
<string name="home" msgid="8263346537524314127">"Plocha"</string>
<string name="charge_length_format" msgid="8978516217024434156">"před <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Zbývající čas: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 398875a..d1d7b23 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Oplader ikke"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Fuld"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolleret af administratoren"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Aktiveret af administratoren"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Deaktiveret af administratoren"</string>
<string name="home" msgid="8263346537524314127">"Start"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> siden"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> tilbage"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 2a56425..fbd1207 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Wird nicht geladen"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Voll"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Durch den Administrator verwaltet"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Vom Administrator aktiviert"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Vom Administrator deaktiviert"</string>
<string name="home" msgid="8263346537524314127">"Startseite"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Vor <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Noch <xliff:g id="ID_1">%1$s</xliff:g> verbleibend"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index dd6bb4f..dce2cf7 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Δεν φορτίζει"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Πλήρης"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Ελέγχονται από το διαχειριστή"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Ενεργοποιήθηκε από το διαχειριστή"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Απενεργοποιήθηκε από το διαχειριστή"</string>
<string name="home" msgid="8263346537524314127">"Αρχική οθόνη"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Πριν από <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Απομένουν <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 1ed6dbd..4821a71 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Not charging"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Enabled by administrator"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Disabled by administrator"</string>
<string name="home" msgid="8263346537524314127">"Home"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ago"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> left"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 1ed6dbd..4821a71 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Not charging"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Enabled by administrator"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Disabled by administrator"</string>
<string name="home" msgid="8263346537524314127">"Home"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ago"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> left"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 1ed6dbd..4821a71 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Not charging"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Enabled by administrator"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Disabled by administrator"</string>
<string name="home" msgid="8263346537524314127">"Home"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ago"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> left"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 3f2befd..2d0ce02 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"No se realiza la carga"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Cargado"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada por el administrador"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Habilitada por el administrador"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Inhabilitada por el administrador"</string>
<string name="home" msgid="8263346537524314127">"Página principal"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Hace <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Falta <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 57a749d..8dcf6ab 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -278,7 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Ejecuta procesadores de WebView en un proceso aislado."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementación de WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Establecer implementación de WebView"</string>
- <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"La implementación de WebView seleccionada no es válida porque la lista de opciones de implementación no estaba activada. Esta ya debería estar actualizada."</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"La implementación de WebView seleccionada no es válida porque la lista de opciones de implementación estaba inactiva. Esta ya debería estar actualizada."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Convertir a cifrado de archivo"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertir…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Ya está cifrado"</string>
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"No se está cargando"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Completa"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada por el administrador"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Habilitado por el administrador"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Inhabilitado por el administrador"</string>
<string name="home" msgid="8263346537524314127">"Inicio"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Hace <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Tiempo restante: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml
index 27546ce..62dd7ab 100644
--- a/packages/SettingsLib/res/values-et-rEE/strings.xml
+++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ei lae"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Täis"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Juhib administraator"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Administraator on lubanud"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Administraator on keelanud"</string>
<string name="home" msgid="8263346537524314127">"Avaekraan"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> tagasi"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> on jäänud"</string>
diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
index dd0e1cb..cb6f0b4 100644
--- a/packages/SettingsLib/res/values-eu-rES/strings.xml
+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ez da kargatzen ari"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Beteta"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Administratzaileak kontrolatzen du"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Administratzaileak gaitu du"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Administratzaileak desgaitu du"</string>
<string name="home" msgid="8263346537524314127">"Hasierako pantaila"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Duela <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> guztiz kargatu arte"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index a683c55..e7cbd1e 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -274,11 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"فعال. برای تغییر حالت ضربه بزنید."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"سرویسهای در حال اجرا"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"مشاهده و کنترل سرویسهای در حال اجرای فعلی"</string>
- <string name="enable_webview_multiprocess" msgid="3405948012467585908">"فعال کردن WebView چند پردازشی"</string>
- <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"اجرای تولیدکننده تصویر WebView در یک پردازش مجزا."</string>
- <string name="select_webview_provider_title" msgid="4628592979751918907">"اجرای WebView"</string>
- <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"تنظیم اجرای WebView"</string>
- <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"اجرای WebView انتخابی نامعتبر است چون فهرست گزینههای اجرای انتخابی قدیمی شده است. این فهرست اکنون باید بهروزرسانی شود."</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"فعال کردن وبنمای چندپردازشی"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"اجرای تولیدکننده تصویر وبنما در یک پردازش مجزا."</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"اجرای وبنما"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"تنظیم اجرای وبنما"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"اجرای وبنمای انتخابی نامعتبر است چون فهرست گزینههای اجرای انتخابی قدیمی شده است. این فهرست اکنون باید بهروزرسانی شود."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"تبدیل به رمزگذاری برحسب فایل"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"تبدیل…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"از قبل به رمزگذاری بر حسب فایل تبدیل شده است"</string>
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"شارژ نمیشود"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"پر"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"توسط سرپرست سیستم کنترل میشود"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"سرپرست آن را فعال کرده است"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"سرپرست آن را غیرفعال کرده است"</string>
<string name="home" msgid="8263346537524314127">"صفحه اصلی"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> قبل"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> باقی مانده است"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index bb27bcf..bb3ad97 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ei laturissa"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Täynnä"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Järjestelmänvalvoja hallinnoi tätä asetusta."</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Järjestelmänvalvojan käyttöön ottama"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Järjestelmänvalvojan käytöstä poistama"</string>
<string name="home" msgid="8263346537524314127">"Aloitusnäyttö"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> sitten"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> jäljellä"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 7ca3f89..1f12f18 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"N\'est pas en charge"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Pleine"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Contrôlé par l\'administrateur"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Activé par l\'administrateur"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Désactivé par l\'administrateur"</string>
<string name="home" msgid="8263346537524314127">"Accueil"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Il y a <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Durée restante :<xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index adfc7a3..3dc2a6a 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Débranchée"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"pleine"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Contrôlé par l\'administrateur"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Activé par l\'administrateur"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Désactivé par l\'administrateur"</string>
<string name="home" msgid="8263346537524314127">"Accueil"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Il y a <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Il reste <xliff:g id="ID_1">%1$s</xliff:g>."</string>
diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
index 867a29d..3715919 100644
--- a/packages/SettingsLib/res/values-gl-rES/strings.xml
+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Non está cargando"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Completa"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Opción controlada polo administrador"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Activado polo administrador"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Desactivado polo administrador"</string>
<string name="home" msgid="8263346537524314127">"Inicio"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Hai <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Tempo restante: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
index 54e7288..c77aeb6 100644
--- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ચાર્જ થઈ રહ્યું નથી"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"પૂર્ણ"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"વ્યવસ્થાપક દ્વારા નિયંત્રિત"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"વ્યવસ્થાપક દ્વારા સક્ષમ કરેલ"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"વ્યવસ્થાપક દ્વારા અક્ષમ કરેલ"</string>
<string name="home" msgid="8263346537524314127">"હોમ"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> પહેલાં"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> બાકી"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index a7e838e..e8a47cb 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"चार्ज नहीं हो रही है"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"पूरी"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"व्यवस्थापक द्वारा नियंत्रित"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"व्यवस्थापक द्वारा सक्षम किया गया"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"व्यवस्थापक द्वारा अक्षम किया गया"</string>
<string name="home" msgid="8263346537524314127">"होम"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> पहले"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> शेष"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index f315fe9..320ebc1 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ne puni se"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Puna"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolira administrator"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Omogućio administrator"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Onemogućio administrator"</string>
<string name="home" msgid="8263346537524314127">"Početni zaslon"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Prije <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Još <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 9b62eb1..4ea4528 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nem töltődik"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Feltöltve"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Rendszergazda által irányítva"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Engedélyezve a rendszergazda által"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Letiltva a rendszergazda által"</string>
<string name="home" msgid="8263346537524314127">"Főoldal"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Ennyi ideje: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> van hátra"</string>
diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
index 36a3813..046ea48 100644
--- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Չի լիցքավորվում"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Լիցքավորված"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Վերահսկվում է ադմինիստրատորի կողմից"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Միացված է ադմինիստրատորի կողմից"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Կասեցված է ադմինիստրատորի կողմից"</string>
<string name="home" msgid="8263346537524314127">"Գլխավոր էջ"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> առաջ"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Մնացել է <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 62372ee..02c747a 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Tidak mengisi daya"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Penuh"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Dikontrol oleh admin"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Diaktifkan oleh administrator"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Dinonaktifkan oleh administrator"</string>
<string name="home" msgid="8263346537524314127">"Layar Utama"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> lalu"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Tersisa <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
index cd8734d..17a2f08 100644
--- a/packages/SettingsLib/res/values-is-rIS/strings.xml
+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ekki í hleðslu"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Fullhlaðin"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Stjórnað af kerfisstjóra"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Virkjað af stjórnanda"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Stjórnandi gerði óvirkt"</string>
<string name="home" msgid="8263346537524314127">"Heim"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Fyrir <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> eftir"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 44bffcb..9c75939 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Non in carica"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Carica"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Gestita dall\'amministratore"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Attivata dall\'amministratore"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Disattivata dall\'amministratore"</string>
<string name="home" msgid="8263346537524314127">"Home page"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> fa"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> rimanenti"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index de7f7e3..429ce61 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"לא טוען"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"מלא"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"נמצא בשליטת מנהל מערכת"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"הופעל על ידי מנהל המערכת"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"הושבת על ידי מנהל המערכת"</string>
<string name="home" msgid="8263346537524314127">"דף הבית"</string>
<string name="charge_length_format" msgid="8978516217024434156">"לפני <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"נשארו <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index f341d71..6c42110 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -313,6 +313,8 @@
<!-- no translation found for battery_info_status_full (2824614753861462808) -->
<skip />
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"管理者により管理されています"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"管理者によって有効にされています"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"管理者によって無効にされています"</string>
<string name="home" msgid="8263346537524314127">"ホーム"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"あと <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
index 08e6327..6dba53b 100644
--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"არ იტენება"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ბატარეა დატენილია"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"იმართება ადმინისტრატორის მიერ"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"ჩართულია ადმინისტრატორის მიერ"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"გათიშულია ადმინისტრატორის მიერ"</string>
<string name="home" msgid="8263346537524314127">"მთავარი"</string>
<string name="charge_length_format" msgid="8978516217024434156">"გავიდა <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"დარჩენილია <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
index 921812a..36843fd 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Зарядталып тұрған жоқ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Толық"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Әкімші басқарады"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Әкімші қосқан"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Әкімші өшірген"</string>
<string name="home" msgid="8263346537524314127">"Негізгі бет"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> бұрын"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> қалды"</string>
diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml
index f64158c..9985a1e 100644
--- a/packages/SettingsLib/res/values-km-rKH/strings.xml
+++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"មិនបញ្ចូលថ្ម"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ពេញ"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"គ្រប់គ្រងដោយអ្នកគ្រប់គ្រង"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"បានបើកដំណើរការដោយអ្នកគ្រប់គ្រង"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"បានបិទដំណើរការដោយអ្នកគ្រប់គ្រង"</string>
<string name="home" msgid="8263346537524314127">"ដើម"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> មុន"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"នៅសល់ <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
index 7e68655..8ca9807 100644
--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ಚಾರ್ಜ್ ಆಗುತ್ತಿಲ್ಲ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ಭರ್ತಿ"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ನಿರ್ವಾಹಕರ ಮೂಲಕ ನಿಯಂತ್ರಿಸಲಾಗಿದೆ"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"ನಿರ್ವಾಹಕರಿಂದ ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"ನಿರ್ವಾಹಕರಿಂದ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="home" msgid="8263346537524314127">"ಮುಖಪುಟ"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ಹಿಂದೆ"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ಉಳಿದಿದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index a7434d0..31e0378 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"충전 안함"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"충전 완료"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"관리자가 제어"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"관리자가 사용 설정함"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"관리자가 사용 중지함"</string>
<string name="home" msgid="8263346537524314127">"홈"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> 전"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> 남음"</string>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
index e05d82e2..fd2d905 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -278,7 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView рендерерлерин корголгон процессте иштетүү."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView аткарылышы"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView аткарылышын коюу"</string>
- <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Аткарууларды тандоо тизмеси эскирип кеткендиктен тандалган WebView аткарылышы жараксыз. Тизме азыр жаңыртылышы керек."</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Тандалган WebView кызматы колдоого алынбайт. Кызматтардын тизмеси эскирип калгандыктан ал азыр жаңыртылат."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Файл шифрлөөсүнө айландыруу"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Айландыруу…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Файл мурунтан эле шифрленген"</string>
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Кубатталган жок"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Толук"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Администратор тарабынан көзөмөлдөнөт"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Администратор иштетип койгон"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Администратор өчүрүп койгон"</string>
<string name="home" msgid="8263346537524314127">"Башкы бет"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> мурун"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> калды"</string>
diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml
index e9017d9..605f476 100644
--- a/packages/SettingsLib/res/values-lo-rLA/strings.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ບໍ່ໄດ້ສາກໄຟ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ເຕັມ"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ຄວບຄຸມໂດຍຜູ້ເບິ່ງແຍງ"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"ຖືກເປີດໃຊ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບ"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"ຖືກປິດໄວ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບ"</string>
<string name="home" msgid="8263346537524314127">"ໜ້າຫຼັກ"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ກ່ອນນີ້"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"ຍັງເຫຼືອ <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 5c3f5be..253eeb3 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nekraunama"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Visiškai įkrautas"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Valdo administratorius"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Įgalino administratorius"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Išjungė administratorius"</string>
<string name="home" msgid="8263346537524314127">"Pagrindinis ekranas"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Prieš <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Liko <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 27eeaf5..3323cd9 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nenotiek uzlāde"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Pilns"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolē administrators"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Iespējojis administrators"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Atspējojis administrators"</string>
<string name="home" msgid="8263346537524314127">"Sākums"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Pirms šāda laika: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Atlikušais laiks: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
index ec09f21..41c8600 100644
--- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не се полни"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Целосна"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролирано од администраторот"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Овозможено од администраторот"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Оневозможено од администраторот"</string>
<string name="home" msgid="8263346537524314127">"Почетна страница"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Пред <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Преостанаа <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
index 24ad333..80cf43e 100644
--- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ചാർജ്ജുചെയ്യുന്നില്ല"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"നിറഞ്ഞു"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"അഡ്മിൻ നിയന്ത്രിക്കുന്നത്"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"അഡ്മിനിസ്ട്രേറ്റർ പ്രവർത്തനക്ഷമമാക്കി"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"അഡ്മിനിസ്ട്രേറ്റർ പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="home" msgid="8263346537524314127">"ഹോം"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> മുമ്പ്"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml
index 5466ff1..5e7ea15 100644
--- a/packages/SettingsLib/res/values-mn-rMN/strings.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Цэнэглэхгүй байна"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Дүүрэн"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Админ удирдсан"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Админ идэвхтэй болгосон"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Админ идэвхгүй болгосон"</string>
<string name="home" msgid="8263346537524314127">"Нүүр"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> өмнө"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> үлдсэн"</string>
diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
index ab55a3d..7a3d76d 100644
--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"चार्ज होत नाही"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"पूर्ण"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"प्रशासकाने नियंत्रित केलेले"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"प्रशासकाने सक्षम केलेले"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"प्रशासकाने अक्षम केलेले"</string>
<string name="home" msgid="8263346537524314127">"मुख्यपृष्ठ"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> पूर्वी"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> शिल्लक"</string>
diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml
index 01b52c1..3f29687 100644
--- a/packages/SettingsLib/res/values-ms-rMY/strings.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Tidak mengecas"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Penuh"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Dikawal oleh pentadbir"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Didayakan oleh pentadbir"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Dilumpuhkan oleh pentadbir"</string>
<string name="home" msgid="8263346537524314127">"Skrin Utama"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> yang lalu"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> lagi"</string>
diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml
index d3659b7..71862a3 100644
--- a/packages/SettingsLib/res/values-my-rMM/strings.xml
+++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"အားသွင်းမနေပါ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"အပြည့်"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"စီမံခန့်ခွဲသူမှ ထိန်းချုပ်ပါသည်"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"စီမံခန့်ခွဲသူမှ ဖွင့်ထားသည်"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"စီမံခန့်ခွဲသူမှ ပိတ်ထားသည်"</string>
<string name="home" msgid="8263346537524314127">"ပင်မ"</string>
<string name="charge_length_format" msgid="8978516217024434156">"ပြီးခဲ့သည့် <xliff:g id="ID_1">%1$s</xliff:g> က"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ကျန်ပါသည်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 6865d50..2ad14dc 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Lader ikke"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Fullt"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrollert av administratoren"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Slått på av administratoren"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Avslått av administratoren"</string>
<string name="home" msgid="8263346537524314127">"Startside"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> siden"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> gjenstår"</string>
diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
index 7742b9d..6c8dc59 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"चार्ज हुँदै छैन"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"पूर्ण"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"प्रशासकद्वारा नियन्त्रित"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"प्रशासकद्वारा सक्षम गरिएको छ"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"प्रशासकद्वारा असक्षम गरिएको छ"</string>
<string name="home" msgid="8263346537524314127">"गृह"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> पहिले"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> बाँकी"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index efee429..7f9df25 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Wordt niet opgeladen"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Volledig"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Ingesteld door beheerder"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Ingeschakeld door beheerder"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Uitgeschakeld door beheerder"</string>
<string name="home" msgid="8263346537524314127">"Startpagina"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> geleden"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> resterend"</string>
diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
index 15e6635..10d57f4 100644
--- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ਪੂਰੀ"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਕੰਟਰੋਲ ਕੀਤੀ ਗਈ"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਯੋਗ ਬਣਾਈ ਗਈ"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅਯੋਗ ਬਣਾਈ ਗਈ"</string>
<string name="home" msgid="8263346537524314127">"ਮੁੱਖ ਸਕ੍ਰੀਨ"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ਪਹਿਲਾਂ"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ਬਾਕੀ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 9d8d97a..3e89094 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nie podłączony"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Naładowana"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolowane przez administratora"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Włączone przez administratora"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Wyłączone przez administratora"</string>
<string name="home" msgid="8263346537524314127">"Ekran główny"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> temu"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Pozostało <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 844ae41..c772ded 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Não está carregando"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Cheio"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada pelo admin"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Ativada pelo administrador"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Desativada pelo administrador"</string>
<string name="home" msgid="8263346537524314127">"Início"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> atrás"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> restante(s)"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 115f951..2b3dcc7 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Não está a carregar"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Completo"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlado pelo administrador"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Ativado pelo administrador"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Desativado pelo administrador"</string>
<string name="home" msgid="8263346537524314127">"Página inicial"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Há <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Resta(m) <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 844ae41..c772ded 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Não está carregando"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Cheio"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada pelo admin"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Ativada pelo administrador"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Desativada pelo administrador"</string>
<string name="home" msgid="8263346537524314127">"Início"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> atrás"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> restante(s)"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 0faf848..0322f55 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nu încarcă"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Complet"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlată de administrator"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Activată de administrator"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Dezactivată de administrator"</string>
<string name="home" msgid="8263346537524314127">"Ecranul principal"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Acum <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Timp rămas: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 09f792e..7548ace 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не заряжается"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Батарея заряжена"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролируется администратором"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Включено администратором"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Отключено администратором"</string>
<string name="home" msgid="8263346537524314127">"Главная"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> назад"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Осталось <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
index 20cff85..f3d6dc3 100644
--- a/packages/SettingsLib/res/values-si-rLK/strings.xml
+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ආරෝපණය නොවෙමින්"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"පූර්ණ"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"පරිපාලක විසින් පාලනය කරන ලදී"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"පරිපාලක විසින් සබල කරන ලදී"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"පරිපාලක විසින් අබල කරන ලදී"</string>
<string name="home" msgid="8263346537524314127">"මුල් පිටුව"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>කට පෙර"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g>ක් ඉතිරිය"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 5640b13..712c348 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nenabíja sa"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Nabitá"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Ovládané správcom"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Povolené správcom"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Zakázané správcom"</string>
<string name="home" msgid="8263346537524314127">"Domov"</string>
<string name="charge_length_format" msgid="8978516217024434156">"pred <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Zostáva <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index ffe794e..2f23144 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Se ne polni"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Poln"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Nadzira skrbnik"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Omogočil skrbnik"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Onemogočil skrbnik"</string>
<string name="home" msgid="8263346537524314127">"Začetni zaslon"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Pred toliko časa: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Še <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml
index c84430c..853dd2f 100644
--- a/packages/SettingsLib/res/values-sq-rAL/strings.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nuk po ngarkohet"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"E mbushur"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolluar nga administratori"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Aktivizuar nga administratori"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Çaktivizuar nga administratori"</string>
<string name="home" msgid="8263346537524314127">"Kreu"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> më parë"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> të mbetura"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index af3daba..094a405 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не пуни се"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Пуно"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролише администратор"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Омогућио је администратор"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Онемогућио је администратор"</string>
<string name="home" msgid="8263346537524314127">"Почетни"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Пре <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Још <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 1cd9b6f..e12d394 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Laddar inte"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Fullt"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Strys av administratören"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Har aktiverats av administratören"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Har inaktiverats av administratören"</string>
<string name="home" msgid="8263346537524314127">"Startsida"</string>
<string name="charge_length_format" msgid="8978516217024434156">"för <xliff:g id="ID_1">%1$s</xliff:g> sedan"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> kvar"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 24d626c..d5a9d1b 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Haichaji"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Imejaa"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Imedhibitiwa na msimamizi"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Msimamizi amewasha mapendeleo ya mipangilio"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Msimamizi amezima mapendeleo ya mipangilio"</string>
<string name="home" msgid="8263346537524314127">"Mwanzo"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Zimepita <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Zimesalia <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml
index adc75e9..5c7732f 100644
--- a/packages/SettingsLib/res/values-ta-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
@@ -102,7 +102,7 @@
<string name="tts_default_rate_title" msgid="6030550998379310088">"பேச்சு வீதம்"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"பேசப்படும் உரையின் வேகம்"</string>
<string name="tts_default_pitch_title" msgid="6135942113172488671">"ஒலித்திறன்"</string>
- <string name="tts_default_pitch_summary" msgid="1944885882882650009">"தொகுக்கப்பட்ட உரையின் டோன் பாதிக்கப்படும்"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"உருவாக்கப்படும் பேச்சின் டோன் பாதிக்கப்படும்"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"மொழி"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"முறைமையின் மொழியைப் பயன்படுத்து"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"மொழி தேர்ந்தெடுக்கப்படவில்லை"</string>
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"சார்ஜ் ஏறவில்லை"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"முழுமை"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"நிர்வாகி கட்டுப்படுத்துகிறார்"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"நிர்வாகி இயக்கியுள்ளார்"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"நிர்வாகி முடக்கியுள்ளார்"</string>
<string name="home" msgid="8263346537524314127">"முகப்பு"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> முன்"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> உள்ளது"</string>
diff --git a/packages/SettingsLib/res/values-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml
index 4b4aabf..a74fc82 100644
--- a/packages/SettingsLib/res/values-te-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ఛార్జ్ కావడం లేదు"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"నిండింది"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"నిర్వాహకుని ద్వారా నియంత్రించబడింది"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"నిర్వాహకులు ప్రారంభించారు"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"నిర్వాహకులు నిలిపివేసారు"</string>
<string name="home" msgid="8263346537524314127">"హోమ్"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> క్రితం"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> మిగిలి ఉంది"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 6906671..53caea5 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ไม่ได้ชาร์จ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"เต็ม"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ผู้ดูแลระบบเป็นผู้ควบคุม"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"เปิดใช้โดยผู้ดูแลระบบ"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"ปิดใช้โดยผู้ดูแลระบบ"</string>
<string name="home" msgid="8263346537524314127">"หน้าแรก"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>ที่ผ่านมา"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"เหลือ <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index a472075..0c1f167 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Hindi nagkakarga"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Puno"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Pinapamahalaan ng admin"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Na-enable ng administrator"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Na-disable ng administrator"</string>
<string name="home" msgid="8263346537524314127">"Home"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> na ang nakalipas"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> na lang"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 85b6080..230da22 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Şarj etmiyor"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Dolu"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Yönetici tarafından denetleniyor"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Yönetici tarafından etkinleştirildi"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Yönetici tarafından devre dışı bırakıldı"</string>
<string name="home" msgid="8263346537524314127">"Ana Ekran"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> önce"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> kaldı"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 32cd586..01cedc6 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не заряджається"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Акумулятор заряджено"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Керується адміністратором"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Увімкнено адміністратором"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Вимкнено адміністратором"</string>
<string name="home" msgid="8263346537524314127">"Головний екран"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> тому"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Залишилося <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml
index 0eaead8..878ff0c 100644
--- a/packages/SettingsLib/res/values-ur-rPK/strings.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"چارج نہیں ہو رہا ہے"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"مکمل"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"کنٹرول کردہ بذریعہ منتظم"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"منتظم نے فعال کر دیا"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"منتظم نے غیر فعال کر دیا"</string>
<string name="home" msgid="8263346537524314127">"ہوم"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> قبل"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> باقی ہیں"</string>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index 30a8576..d81a041 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Quvvatlanmayapti"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"To‘la"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Administrator tomonidan boshqariladi"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Administrator tomonidan yoqilgan"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Administrator tomonidan o‘chirilgan"</string>
<string name="home" msgid="8263346537524314127">"Bosh ekran"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> oldin"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> qoldi"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 38ddcc0..2b4bddd 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Hiện không sạc"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Đầy"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Do quản trị viên kiểm soát"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Được bật bởi quản trị viên"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Bị tắt bởi quản trị viên"</string>
<string name="home" msgid="8263346537524314127">"Màn hình chính"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> trước"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Còn <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 53bd985..48f03b7 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -278,7 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"在独立进程中运行 WebView 渲染程序。"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 实现"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"设置 WebView 实现"</string>
- <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"所选的 WebView 实现无效,因为相关的实现选项列表已过时。请立即更新这份列表。"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"所选的 WebView 实现无效,因为实现选项列表已过时。请立即更新列表。"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"转换为文件加密"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"转换…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"文件已加密"</string>
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"未在充电"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"电量充足"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"由管理员控制"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"已被管理员启用"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"已被管理员禁用"</string>
<string name="home" msgid="8263346537524314127">"主屏幕"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"还剩 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 02be160..38656e5 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"未開始充電"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"電量已滿"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"已由管理員停用"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"已由管理員啟用"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"已由管理員停用"</string>
<string name="home" msgid="8263346537524314127">"主畫面"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"尚餘 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 7407e28..af83365 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"非充電中"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"電力充足"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"已由管理員停用"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"已由管理員啟用"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"已由管理員停用"</string>
<string name="home" msgid="8263346537524314127">"主畫面"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"還剩 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index e563bff..16841d3 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -311,6 +311,8 @@
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ayishaji"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Kugcwele"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kulawulwa umqondisi"</string>
+ <string name="enabled_by_admin" msgid="2386503803463071894">"Kunikwe amandla umqondisi"</string>
+ <string name="disabled_by_admin" msgid="3669999613095206948">"Ikhutshazwe umlawuli"</string>
<string name="home" msgid="8263346537524314127">"Ekhaya"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> edlule"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> osele"</string>
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/accessibility/AccessibilityUtils.java b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
index 99bd4ad..9268994 100644
--- a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
@@ -22,6 +22,7 @@
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -40,12 +41,21 @@
new TextUtils.SimpleStringSplitter(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR);
/**
- * @return the set of enabled accessibility services. If there are not services
- * it returned the unmodifiable {@link Collections#emptySet()}.
+ * @return the set of enabled accessibility services. If there are no services,
+ * it returns the unmodifiable {@link Collections#emptySet()}.
*/
public static Set<ComponentName> getEnabledServicesFromSettings(Context context) {
- final String enabledServicesSetting = Settings.Secure.getString(
- context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+ return getEnabledServicesFromSettings(context, UserHandle.myUserId());
+ }
+
+ /**
+ * @return the set of enabled accessibility services for {@param userId}. If there are no
+ * services, it returns the unmodifiable {@link Collections#emptySet()}.
+ */
+ public static Set<ComponentName> getEnabledServicesFromSettings(Context context, int userId) {
+ final String enabledServicesSetting = Settings.Secure.getStringForUser(
+ context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ userId);
if (enabledServicesSetting == null) {
return Collections.emptySet();
}
@@ -77,11 +87,22 @@
return langContext.getText(resId);
}
+ /**
+ * Changes an accessibility component's state.
+ */
public static void setAccessibilityServiceState(Context context, ComponentName toggledService,
boolean enabled) {
+ setAccessibilityServiceState(context, toggledService, enabled, UserHandle.myUserId());
+ }
+
+ /**
+ * Changes an accessibility component's state for {@param userId}.
+ */
+ public static void setAccessibilityServiceState(Context context, ComponentName toggledService,
+ boolean enabled, int userId) {
// Parse the enabled services.
Set<ComponentName> enabledServices = AccessibilityUtils.getEnabledServicesFromSettings(
- context);
+ context, userId);
if (enabledServices.isEmpty()) {
enabledServices = new ArraySet<>(1);
@@ -121,13 +142,14 @@
if (enabledServicesBuilderLength > 0) {
enabledServicesBuilder.deleteCharAt(enabledServicesBuilderLength - 1);
}
- Settings.Secure.putString(context.getContentResolver(),
+ Settings.Secure.putStringForUser(context.getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
- enabledServicesBuilder.toString());
+ enabledServicesBuilder.toString(), userId);
// Update accessibility enabled.
- Settings.Secure.putInt(context.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_ENABLED, accessibilityEnabled ? 1 : 0);
+ Settings.Secure.putIntForUser(context.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, accessibilityEnabled ? 1 : 0,
+ userId);
}
private static Set<ComponentName> getInstalledServices(Context context) {
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/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index d89abf42..b79ce80 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -62,8 +62,9 @@
*/
private static final ArraySet<String> sBroadcastOnRestore;
static {
- sBroadcastOnRestore = new ArraySet<String>(3);
+ sBroadcastOnRestore = new ArraySet<String>(4);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+ sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_INPUT_METHODS);
}
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/Shell/res/values-af/strings.xml b/packages/Shell/res/values-af/strings.xml
index 9d399c1..f86b551 100644
--- a/packages/Shell/res/values-af/strings.xml
+++ b/packages/Shell/res/values-af/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Kon nie skermkiekie neem nie."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Foutverslag <xliff:g id="ID">#%d</xliff:g> se besonderhede"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Lêernaam"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Gedetailleerde beskrywing"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Fouttitel"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Foutopsomming"</string>
+ <string name="save" msgid="4781509040564835759">"Stoor"</string>
</resources>
diff --git a/packages/Shell/res/values-am/strings.xml b/packages/Shell/res/values-am/strings.xml
index 2545222..55c5390 100644
--- a/packages/Shell/res/values-am/strings.xml
+++ b/packages/Shell/res/values-am/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ቅጽበታዊ ገጽ እይታ ሊነሳ አይችልም"</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"የሳንካ ሪፖርት <xliff:g id="ID">#%d</xliff:g> ዝርዝሮች"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"የፋይል ስም"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"ርዕስ"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"ዝርዝር መግለጫ"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"የሳንካ ርዕስ"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"የሳንካ ማጠቃለያ"</string>
+ <string name="save" msgid="4781509040564835759">"አስቀምጥ"</string>
</resources>
diff --git a/packages/Shell/res/values-ar/strings.xml b/packages/Shell/res/values-ar/strings.xml
index 7593110..f0af8ce 100644
--- a/packages/Shell/res/values-ar/strings.xml
+++ b/packages/Shell/res/values-ar/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"تعذر التقاط لقطة الشاشة."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"تفاصيل تقرير الخطأ <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"اسم الملف"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"العنوان"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"وصف تفصيلي"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"عنوان الخطأ"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"ملخص الخطأ"</string>
+ <string name="save" msgid="4781509040564835759">"حفظ"</string>
</resources>
diff --git a/packages/Shell/res/values-az-rAZ/strings.xml b/packages/Shell/res/values-az-rAZ/strings.xml
index 9130255..6d375fe 100644
--- a/packages/Shell/res/values-az-rAZ/strings.xml
+++ b/packages/Shell/res/values-az-rAZ/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Displey görüntüsü əlçatan deyil."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Baq hesabatı <xliff:g id="ID">#%d</xliff:g> detalları"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Fayl adı"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Başlıq"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Ətraflı təsvir"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Baq başlığı"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Baq xülasə"</string>
+ <string name="save" msgid="4781509040564835759">"Yadda saxlayın"</string>
</resources>
diff --git a/packages/Shell/res/values-b+sr+Latn/strings.xml b/packages/Shell/res/values-b+sr+Latn/strings.xml
index 597e545..ad84941 100644
--- a/packages/Shell/res/values-b+sr+Latn/strings.xml
+++ b/packages/Shell/res/values-b+sr+Latn/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snimanje ekrana nije uspelo."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalji izveštaja o grešci <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Naziv datoteke"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljni opis"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Naslov greške"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Rezime greške"</string>
+ <string name="save" msgid="4781509040564835759">"Sačuvaj"</string>
</resources>
diff --git a/packages/Shell/res/values-bg/strings.xml b/packages/Shell/res/values-bg/strings.xml
index 6ca7914..e543839 100644
--- a/packages/Shell/res/values-bg/strings.xml
+++ b/packages/Shell/res/values-bg/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Екранната снимка не можа да бъде направена."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Подробности за сигнала за програмна грешка „<xliff:g id="ID">#%d</xliff:g>“"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Име на файла"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Заглавие"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Подробно описание"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Заглавие на сигнала за програмна грешка"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Обобщена информация за сигнала за програмна грешка"</string>
+ <string name="save" msgid="4781509040564835759">"Запазване"</string>
</resources>
diff --git a/packages/Shell/res/values-bn-rBD/strings.xml b/packages/Shell/res/values-bn-rBD/strings.xml
index 5390315..bba778d 100644
--- a/packages/Shell/res/values-bn-rBD/strings.xml
+++ b/packages/Shell/res/values-bn-rBD/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"স্ক্রীনশট নেওয়া যায়নি৷"</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ত্রুটির প্রতিবেদন <xliff:g id="ID">#%d</xliff:g> এর বিশদ বিবরণ"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ফাইলের নাম"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"শীর্ষক"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"বিস্তারিত বিবরণ"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"ত্রুটির শীর্ষক"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"ত্রুটির সারাংশ"</string>
+ <string name="save" msgid="4781509040564835759">"সংরক্ষণ করুন"</string>
</resources>
diff --git a/packages/Shell/res/values-bs-rBA/strings.xml b/packages/Shell/res/values-bs-rBA/strings.xml
index 903c2ab..54be955 100644
--- a/packages/Shell/res/values-bs-rBA/strings.xml
+++ b/packages/Shell/res/values-bs-rBA/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekran nije moguće snimiti."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalji izvještaja o grešci <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Naziv fajla"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljan opis"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Naslov greške"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Sažetak greške"</string>
+ <string name="save" msgid="4781509040564835759">"Sačuvaj"</string>
</resources>
diff --git a/packages/Shell/res/values-ca/strings.xml b/packages/Shell/res/values-ca/strings.xml
index 0836946..a92177e 100644
--- a/packages/Shell/res/values-ca/strings.xml
+++ b/packages/Shell/res/values-ca/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No s\'ha pogut fer la captura de pantalla."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalls de l\'informe d\'errors <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nom del fitxer"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Títol"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Descripció detallada"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Títol de l\'error"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Resum d\'errors"</string>
+ <string name="save" msgid="4781509040564835759">"Desa"</string>
</resources>
diff --git a/packages/Shell/res/values-cs/strings.xml b/packages/Shell/res/values-cs/strings.xml
index 215ec87..6f7549a 100644
--- a/packages/Shell/res/values-cs/strings.xml
+++ b/packages/Shell/res/values-cs/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snímek obrazovky se nepodařilo pořídit."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Podrobnosti zprávy o chybě <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Název souboru"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Název"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Podrobný popis"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Název chyby"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Přehled chyby"</string>
+ <string name="save" msgid="4781509040564835759">"Uložit"</string>
</resources>
diff --git a/packages/Shell/res/values-da/strings.xml b/packages/Shell/res/values-da/strings.xml
index e956d3a..72a9a99 100644
--- a/packages/Shell/res/values-da/strings.xml
+++ b/packages/Shell/res/values-da/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Der kunne ikke tages et skærmbillede."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Oplysninger om fejlrapporten <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Filnavn"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljeret beskrivelse"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Fejlrapportens titel"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Oversigt over fejl"</string>
+ <string name="save" msgid="4781509040564835759">"Gem"</string>
</resources>
diff --git a/packages/Shell/res/values-de/strings.xml b/packages/Shell/res/values-de/strings.xml
index 07f8898..f848c9d 100644
--- a/packages/Shell/res/values-de/strings.xml
+++ b/packages/Shell/res/values-de/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot konnte nicht aufgenommen werden."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Details zum Fehlerbericht <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Dateiname"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Detaillierte Beschreibung"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Titel des Programmfehlers"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Zusammenfassung des Programmfehlers"</string>
+ <string name="save" msgid="4781509040564835759">"Speichern"</string>
</resources>
diff --git a/packages/Shell/res/values-el/strings.xml b/packages/Shell/res/values-el/strings.xml
index 6746976..0c04809 100644
--- a/packages/Shell/res/values-el/strings.xml
+++ b/packages/Shell/res/values-el/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Δεν ήταν δυνατή η λήψη του στιγμιότυπου οθόνης."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Λεπτομέρειες της αναφοράς σφάλματος <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Όνομα αρχείου"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Τίτλος"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Αναλυτική περιγραφή"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Τίτλος σφάλματος"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Περίληψη σφάλματος"</string>
+ <string name="save" msgid="4781509040564835759">"Αποθήκευση"</string>
</resources>
diff --git a/packages/Shell/res/values-en-rAU/strings.xml b/packages/Shell/res/values-en-rAU/strings.xml
index ac681e2..ad637f5 100644
--- a/packages/Shell/res/values-en-rAU/strings.xml
+++ b/packages/Shell/res/values-en-rAU/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Bug report <xliff:g id="ID">#%d</xliff:g> details"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Title"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Bug title"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Bug summary"</string>
+ <string name="save" msgid="4781509040564835759">"Save"</string>
</resources>
diff --git a/packages/Shell/res/values-en-rGB/strings.xml b/packages/Shell/res/values-en-rGB/strings.xml
index ac681e2..ad637f5 100644
--- a/packages/Shell/res/values-en-rGB/strings.xml
+++ b/packages/Shell/res/values-en-rGB/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Bug report <xliff:g id="ID">#%d</xliff:g> details"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Title"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Bug title"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Bug summary"</string>
+ <string name="save" msgid="4781509040564835759">"Save"</string>
</resources>
diff --git a/packages/Shell/res/values-en-rIN/strings.xml b/packages/Shell/res/values-en-rIN/strings.xml
index ac681e2..ad637f5 100644
--- a/packages/Shell/res/values-en-rIN/strings.xml
+++ b/packages/Shell/res/values-en-rIN/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Bug report <xliff:g id="ID">#%d</xliff:g> details"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Title"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Bug title"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Bug summary"</string>
+ <string name="save" msgid="4781509040564835759">"Save"</string>
</resources>
diff --git a/packages/Shell/res/values-es-rUS/strings.xml b/packages/Shell/res/values-es-rUS/strings.xml
index 96ca14c..a9a1e08 100644
--- a/packages/Shell/res/values-es-rUS/strings.xml
+++ b/packages/Shell/res/values-es-rUS/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No se pudo tomar la captura de pantalla."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalles del informe de errores <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nombre del archivo"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Descripción completa"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Título del error"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Resumen del error"</string>
+ <string name="save" msgid="4781509040564835759">"Guardar"</string>
</resources>
diff --git a/packages/Shell/res/values-es/strings.xml b/packages/Shell/res/values-es/strings.xml
index 00874c6..b82d372 100644
--- a/packages/Shell/res/values-es/strings.xml
+++ b/packages/Shell/res/values-es/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No se puede realizar la captura de pantalla."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalles del informe de errores <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nombre de archivo"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Descripción completa"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Nombre del informe de errores"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Resumen del informe de errores"</string>
+ <string name="save" msgid="4781509040564835759">"Guardar"</string>
</resources>
diff --git a/packages/Shell/res/values-et-rEE/strings.xml b/packages/Shell/res/values-et-rEE/strings.xml
index bc469bc..cdb774a0 100644
--- a/packages/Shell/res/values-et-rEE/strings.xml
+++ b/packages/Shell/res/values-et-rEE/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekraanipilti ei saanud teha."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Veaaruande <xliff:g id="ID">#%d</xliff:g> üksikasjad"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Faili nimi"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Pealkiri"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Üksikasjalik kirjeldus"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Vea pealkiri"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Vea kokkuvõte"</string>
+ <string name="save" msgid="4781509040564835759">"Salvesta"</string>
</resources>
diff --git a/packages/Shell/res/values-eu-rES/strings.xml b/packages/Shell/res/values-eu-rES/strings.xml
index 614f17e..42dfe27 100644
--- a/packages/Shell/res/values-eu-rES/strings.xml
+++ b/packages/Shell/res/values-eu-rES/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ezin izan da atera pantaila-argazkia."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Akatsen <xliff:g id="ID">#%d</xliff:g> txostenaren xehetasunak"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Fitxategi-izena"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Izena"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Azalpen xehatua"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Akatsaren izena"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Akatsaren laburpena"</string>
+ <string name="save" msgid="4781509040564835759">"Gorde"</string>
</resources>
diff --git a/packages/Shell/res/values-fa/strings.xml b/packages/Shell/res/values-fa/strings.xml
index ab00562..e825f3a 100644
--- a/packages/Shell/res/values-fa/strings.xml
+++ b/packages/Shell/res/values-fa/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"نمیتوان عکس صفحهنمایش گرفت."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"جزئیات گزارش اشکال <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"نام فایل"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"عنوان"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"جزئیات دقیق"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"عنوان اشکال"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"خلاصه اشکال"</string>
+ <string name="save" msgid="4781509040564835759">"ذخیره کردن"</string>
</resources>
diff --git a/packages/Shell/res/values-fi/strings.xml b/packages/Shell/res/values-fi/strings.xml
index be7aabd..8c67c66 100644
--- a/packages/Shell/res/values-fi/strings.xml
+++ b/packages/Shell/res/values-fi/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Kuvakaappauksen tallentaminen epäonnistui."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Virheraportin <xliff:g id="ID">#%d</xliff:g> tiedot"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Tiedostonimi"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Otsikko"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Yksityiskohtainen kuvaus"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Virheen nimi"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Virheen yhteenveto"</string>
+ <string name="save" msgid="4781509040564835759">"Tallenna"</string>
</resources>
diff --git a/packages/Shell/res/values-fr-rCA/strings.xml b/packages/Shell/res/values-fr-rCA/strings.xml
index 7d9f97d..3daa120 100644
--- a/packages/Shell/res/values-fr-rCA/strings.xml
+++ b/packages/Shell/res/values-fr-rCA/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Une erreur s\'est produite lors de la saisie d\'écran."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Détails du rapport de bogue <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nom de fichier"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Titre"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Description détaillée"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Titre du bogue"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Sommaire des bogues"</string>
+ <string name="save" msgid="4781509040564835759">"Enregistrer"</string>
</resources>
diff --git a/packages/Shell/res/values-fr/strings.xml b/packages/Shell/res/values-fr/strings.xml
index 74025d9..c512aca 100644
--- a/packages/Shell/res/values-fr/strings.xml
+++ b/packages/Shell/res/values-fr/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Impossible d\'effectuer une capture d\'écran."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Informations sur le rapport de bug \"<xliff:g id="ID">#%d</xliff:g>\""</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nom de fichier"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Titre"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Description détaillée"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Titre du bug"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Résumé du bug"</string>
+ <string name="save" msgid="4781509040564835759">"Enregistrer"</string>
</resources>
diff --git a/packages/Shell/res/values-gl-rES/strings.xml b/packages/Shell/res/values-gl-rES/strings.xml
index d3be7c5..ea95c97 100644
--- a/packages/Shell/res/values-gl-rES/strings.xml
+++ b/packages/Shell/res/values-gl-rES/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Non se puido realizar a captura de pantalla."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalles do informe de erros <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nome do ficheiro"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Descrición detallada"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Título do informe de erros"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Resumo do informe de erros"</string>
+ <string name="save" msgid="4781509040564835759">"Gardar"</string>
</resources>
diff --git a/packages/Shell/res/values-gu-rIN/strings.xml b/packages/Shell/res/values-gu-rIN/strings.xml
index 45df7b3..1436c3d 100644
--- a/packages/Shell/res/values-gu-rIN/strings.xml
+++ b/packages/Shell/res/values-gu-rIN/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"સ્ક્રીનશોટ લઇ શકાયો નથી."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"બગ રિપોર્ટ <xliff:g id="ID">#%d</xliff:g> ની વિગતો"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ફાઇલનું નામ"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"શીર્ષક"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"વિગતવાર વર્ણન"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"બગનું શીર્ષક"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"બગનો સારાંશ"</string>
+ <string name="save" msgid="4781509040564835759">"સાચવો"</string>
</resources>
diff --git a/packages/Shell/res/values-hi/strings.xml b/packages/Shell/res/values-hi/strings.xml
index 8858bc3..9a735f2 100644
--- a/packages/Shell/res/values-hi/strings.xml
+++ b/packages/Shell/res/values-hi/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रीनशॉट नहीं लिया जा सका."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> के विवरण"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"फ़ाइल नाम"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"शीर्षक"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"विस्तृत वर्णन"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"बग शीर्षक"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"बग सारांश"</string>
+ <string name="save" msgid="4781509040564835759">"सहेजें"</string>
</resources>
diff --git a/packages/Shell/res/values-hr/strings.xml b/packages/Shell/res/values-hr/strings.xml
index cb03f9c..71d50b8 100644
--- a/packages/Shell/res/values-hr/strings.xml
+++ b/packages/Shell/res/values-hr/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snimanje zaslona nije uspjelo."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Pojedinosti izvješća o programskoj pogrešci <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Naziv datoteke"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljan opis"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Naslov izvješća o programskoj pogrešci"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Sažetak izvješća o programskoj pogrešci"</string>
+ <string name="save" msgid="4781509040564835759">"Spremi"</string>
</resources>
diff --git a/packages/Shell/res/values-hu/strings.xml b/packages/Shell/res/values-hu/strings.xml
index 390cd2f..cf10315 100644
--- a/packages/Shell/res/values-hu/strings.xml
+++ b/packages/Shell/res/values-hu/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nem sikerült elkészíteni a képernyőképet."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Hibajelentés (<xliff:g id="ID">#%d</xliff:g>) részletei"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Fájlnév"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Név"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Részletes leírás"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Hibajelentés címe"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Hibajelentés összefoglalója"</string>
+ <string name="save" msgid="4781509040564835759">"Mentés"</string>
</resources>
diff --git a/packages/Shell/res/values-hy-rAM/strings.xml b/packages/Shell/res/values-hy-rAM/strings.xml
index 68478ab..1cf5c94 100644
--- a/packages/Shell/res/values-hy-rAM/strings.xml
+++ b/packages/Shell/res/values-hy-rAM/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Չհաջողվեց ստանալ էկրանի պատկերը:"</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"<xliff:g id="ID">#%d</xliff:g> վրիպակի զեկույցի մանրամասները"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Ֆայլի անունը"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Անվանումը"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Մանրամասն նկարագրություն"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Վրիպակի զեկույցի վերնագիրը"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Վրիպակի զեկույցի ամփոփագիրը"</string>
+ <string name="save" msgid="4781509040564835759">"Պահել"</string>
</resources>
diff --git a/packages/Shell/res/values-in/strings.xml b/packages/Shell/res/values-in/strings.xml
index 4416fc7..1e8fe87 100644
--- a/packages/Shell/res/values-in/strings.xml
+++ b/packages/Shell/res/values-in/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Tangkapan layar tidak dapat diambil."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detail laporan bug <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nama file"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Judul"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Deskripsi detail"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Judul bug"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Ringkasan bug"</string>
+ <string name="save" msgid="4781509040564835759">"Simpan"</string>
</resources>
diff --git a/packages/Shell/res/values-is-rIS/strings.xml b/packages/Shell/res/values-is-rIS/strings.xml
index 0d43719..afcea59 100644
--- a/packages/Shell/res/values-is-rIS/strings.xml
+++ b/packages/Shell/res/values-is-rIS/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekki tókst að taka skjámynd."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Upplýsingar villutilkynningar <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Skráarheiti"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Titill"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Ítarleg lýsing"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Heiti villu"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Villusamantekt"</string>
+ <string name="save" msgid="4781509040564835759">"Vista"</string>
</resources>
diff --git a/packages/Shell/res/values-it/strings.xml b/packages/Shell/res/values-it/strings.xml
index fc9383a..d7ac9a5 100644
--- a/packages/Shell/res/values-it/strings.xml
+++ b/packages/Shell/res/values-it/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Impossibile acquisire lo screenshot."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Dettagli sulla segnalazione di bug <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nome file"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Titolo"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Descrizione dettagliata"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Titolo bug"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Riepilogo bug"</string>
+ <string name="save" msgid="4781509040564835759">"Salva"</string>
</resources>
diff --git a/packages/Shell/res/values-iw/strings.xml b/packages/Shell/res/values-iw/strings.xml
index 335a2e8..fd64ee1 100644
--- a/packages/Shell/res/values-iw/strings.xml
+++ b/packages/Shell/res/values-iw/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"לא ניתן היה לצלם מסך."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"פרטי הדוח על הבאג <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"שם קובץ"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"כותרת"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"תיאור מפורט"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"כותרת הבאג"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"סיכום הבאג"</string>
+ <string name="save" msgid="4781509040564835759">"שמור"</string>
</resources>
diff --git a/packages/Shell/res/values-ja/strings.xml b/packages/Shell/res/values-ja/strings.xml
index b98b05f..050c5df 100644
--- a/packages/Shell/res/values-ja/strings.xml
+++ b/packages/Shell/res/values-ja/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"スクリーンショットを撮影できませんでした。"</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"バグレポート <xliff:g id="ID">#%d</xliff:g> の詳細"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ファイル名"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"タイトル"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"詳細説明"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"バグのタイトル"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"バグの概要"</string>
+ <string name="save" msgid="4781509040564835759">"保存"</string>
</resources>
diff --git a/packages/Shell/res/values-ka-rGE/strings.xml b/packages/Shell/res/values-ka-rGE/strings.xml
index 24d83a4..8c5c6fb 100644
--- a/packages/Shell/res/values-ka-rGE/strings.xml
+++ b/packages/Shell/res/values-ka-rGE/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ეკრანის ანაბეჭდის გადაღება ვერ მოხერხდა."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ხარვეზების შესახებ ანგარიში <xliff:g id="ID">#%d</xliff:g>-ის დეტალები"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ფაილის სახელი"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"სათაური"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"დეტალური აღწერა"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"შეცდომის სათაური"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"შეცდომის რეზიუმე"</string>
+ <string name="save" msgid="4781509040564835759">"შენახვა"</string>
</resources>
diff --git a/packages/Shell/res/values-kk-rKZ/strings.xml b/packages/Shell/res/values-kk-rKZ/strings.xml
index 5878b17..edb2dd0 100644
--- a/packages/Shell/res/values-kk-rKZ/strings.xml
+++ b/packages/Shell/res/values-kk-rKZ/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Скриншот түсіру мүмкін болмады."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"<xliff:g id="ID">#%d</xliff:g> қате туралы есебі туралы мәліметтер"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Файл атауы"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Атауы"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Егжей-тегжейлі сипаттама"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Қатенің атауы"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Қате туралы жиынтық мәліметтер"</string>
+ <string name="save" msgid="4781509040564835759">"Сақтау"</string>
</resources>
diff --git a/packages/Shell/res/values-km-rKH/strings.xml b/packages/Shell/res/values-km-rKH/strings.xml
index 9c95e98..ba0de9f 100644
--- a/packages/Shell/res/values-km-rKH/strings.xml
+++ b/packages/Shell/res/values-km-rKH/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"មិនអាចថតរូបថតអេក្រង់បានទេ"</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ព័ត៌មានលម្អិតពី <xliff:g id="ID">#%d</xliff:g> របាយការណ៍កំហុស"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ឈ្មោះឯកសារ"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"ចំណងជើង"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"ការពិពណ៌នាលម្អិត"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"ចំណងជើងកំហុស"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"សង្ខេបកំហុស"</string>
+ <string name="save" msgid="4781509040564835759">"រក្សាទុក"</string>
</resources>
diff --git a/packages/Shell/res/values-kn-rIN/strings.xml b/packages/Shell/res/values-kn-rIN/strings.xml
index ce6f3c0..b041f35 100644
--- a/packages/Shell/res/values-kn-rIN/strings.xml
+++ b/packages/Shell/res/values-kn-rIN/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ತೆಗೆದುಕೊಳ್ಳಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ದೋಷ ವರದಿಯ <xliff:g id="ID">#%d</xliff:g> ವಿವರಗಳು"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ಫೈಲ್ಹೆಸರು"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"ಶೀರ್ಷಿಕೆ"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"ವಿವರವಾದ ವಿವರಣೆ"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"ಬಗ್ ಶೀರ್ಷಿಕೆ"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"ಬಗ್ ಸಾರಾಂಶ"</string>
+ <string name="save" msgid="4781509040564835759">"ಉಳಿಸು"</string>
</resources>
diff --git a/packages/Shell/res/values-ko/strings.xml b/packages/Shell/res/values-ko/strings.xml
index 70df8e2..2a86360 100644
--- a/packages/Shell/res/values-ko/strings.xml
+++ b/packages/Shell/res/values-ko/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"스크린샷을 찍을 수 없습니다."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"버그 신고 <xliff:g id="ID">#%d</xliff:g> 세부정보"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"파일 이름"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"제목"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"자세한 설명"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"버그 제목"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"버그 요약"</string>
+ <string name="save" msgid="4781509040564835759">"저장"</string>
</resources>
diff --git a/packages/Shell/res/values-ky-rKG/strings.xml b/packages/Shell/res/values-ky-rKG/strings.xml
index 49d8d8d..c701b7e 100644
--- a/packages/Shell/res/values-ky-rKG/strings.xml
+++ b/packages/Shell/res/values-ky-rKG/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Скриншот тартылбай койду."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Мүчүлүштүк тууралуу билдирүүнүн <xliff:g id="ID">#%d</xliff:g> чоо-жайы"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Файлдын аталышы"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Аталышы"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Кененирээк маалымат"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Мүчүлүштүктүн аталышы"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Мүчүлүштүк корутундусу"</string>
+ <string name="save" msgid="4781509040564835759">"Сактоо"</string>
</resources>
diff --git a/packages/Shell/res/values-lo-rLA/strings.xml b/packages/Shell/res/values-lo-rLA/strings.xml
index 61b06c8..4348250 100644
--- a/packages/Shell/res/values-lo-rLA/strings.xml
+++ b/packages/Shell/res/values-lo-rLA/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ບໍ່ສາມາດຖ່າຍພາບໜ້າຈໍໄດ້."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ລາຍລະອຽດຂອງລາຍງານຂໍ້ຜິດພາດ <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ຊື່ໄຟລ໌"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"ຊື່"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"ຄຳອະທິບາຍແບບລະອຽດ"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"ຊື່ຂໍ້ຜິດພາດ"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"ສະຫຼຸບຂໍ້ຜິດພາດ"</string>
+ <string name="save" msgid="4781509040564835759">"ບັນທຶກ"</string>
</resources>
diff --git a/packages/Shell/res/values-lt/strings.xml b/packages/Shell/res/values-lt/strings.xml
index 3418213..a714efc 100644
--- a/packages/Shell/res/values-lt/strings.xml
+++ b/packages/Shell/res/values-lt/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nepavyko padaryti ekrano kopijos."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Išsami informacija apie pranešimą apie riktą (<xliff:g id="ID">#%d</xliff:g>)"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Failo pavadinimas"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Pavadinimas"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Išsamus aprašas"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Rikto pavadinimas"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Rikto suvestinė"</string>
+ <string name="save" msgid="4781509040564835759">"Išsaugoti"</string>
</resources>
diff --git a/packages/Shell/res/values-lv/strings.xml b/packages/Shell/res/values-lv/strings.xml
index 6108716..880d651 100644
--- a/packages/Shell/res/values-lv/strings.xml
+++ b/packages/Shell/res/values-lv/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nevarēja veikt ekrānuzņēmumu."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Kļūdas pārskats <xliff:g id="ID">#%d</xliff:g>: detalizēta informācija"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Faila nosaukums"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Nosaukums"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Detalizēts apraksts"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Kļūdas nosaukums"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Kļūdas kopsavilkums"</string>
+ <string name="save" msgid="4781509040564835759">"Saglabāt"</string>
</resources>
diff --git a/packages/Shell/res/values-mk-rMK/strings.xml b/packages/Shell/res/values-mk-rMK/strings.xml
index 500196d..478c189 100644
--- a/packages/Shell/res/values-mk-rMK/strings.xml
+++ b/packages/Shell/res/values-mk-rMK/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не може да се направи слика од екранот."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Детали за извештајот за грешки <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Име на датотека"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Наслов"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Детален опис"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Наслов на грешката"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Преглед на грешката"</string>
+ <string name="save" msgid="4781509040564835759">"Зачувај"</string>
</resources>
diff --git a/packages/Shell/res/values-ml-rIN/strings.xml b/packages/Shell/res/values-ml-rIN/strings.xml
index 696aab2..70e6333 100644
--- a/packages/Shell/res/values-ml-rIN/strings.xml
+++ b/packages/Shell/res/values-ml-rIN/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"സ്ക്രീൻഷോട്ട് എടുക്കാൻ കഴിഞ്ഞില്ല."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ബഗ് റിപ്പോർട്ട് <xliff:g id="ID">#%d</xliff:g> വിശദാംശങ്ങൾ"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ഫയല്നാമം"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"പേര്"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"വിശദമായ വിവരണം"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"ബഗിന്റെ പേര്"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"ബഗ് സംഗ്രഹം"</string>
+ <string name="save" msgid="4781509040564835759">"സംരക്ഷിക്കുക"</string>
</resources>
diff --git a/packages/Shell/res/values-mn-rMN/strings.xml b/packages/Shell/res/values-mn-rMN/strings.xml
index 62d83cb..49196a2 100644
--- a/packages/Shell/res/values-mn-rMN/strings.xml
+++ b/packages/Shell/res/values-mn-rMN/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Дэлгэцийн зураг авах боломжгүй."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Програмд гарсан алдааны мэдээллийн <xliff:g id="ID">#%d</xliff:g>-ны дэлгэрэнгүй"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Файлын нэр"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Гарчиг"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Дэлгэрэнгүй тайлбар"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Алдааны нэр"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Алдааны хураангуй"</string>
+ <string name="save" msgid="4781509040564835759">"Хадгалах"</string>
</resources>
diff --git a/packages/Shell/res/values-mr-rIN/strings.xml b/packages/Shell/res/values-mr-rIN/strings.xml
index e6b2b04..19a8706 100644
--- a/packages/Shell/res/values-mr-rIN/strings.xml
+++ b/packages/Shell/res/values-mr-rIN/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रीनशॉट घेणे शक्य झाले नाही."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"दोष अहवाल <xliff:g id="ID">#%d</xliff:g> तपशील"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"फाईलनाव"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"शीर्षक"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"तपशीलवार वर्णन"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"दोष शीर्षक"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"दोष सारांश"</string>
+ <string name="save" msgid="4781509040564835759">"जतन करा"</string>
</resources>
diff --git a/packages/Shell/res/values-ms-rMY/strings.xml b/packages/Shell/res/values-ms-rMY/strings.xml
index 1d04253..c9f5375 100644
--- a/packages/Shell/res/values-ms-rMY/strings.xml
+++ b/packages/Shell/res/values-ms-rMY/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Tangkapan skrin tidak dapat diambil."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Butiran laporan pepijat <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nama fail"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Tajuk"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Perihalan terperinci"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Tajuk pepijat"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Ringkasan pepijat"</string>
+ <string name="save" msgid="4781509040564835759">"Simpan"</string>
</resources>
diff --git a/packages/Shell/res/values-my-rMM/strings.xml b/packages/Shell/res/values-my-rMM/strings.xml
index f63c8c5..4250eda 100644
--- a/packages/Shell/res/values-my-rMM/strings.xml
+++ b/packages/Shell/res/values-my-rMM/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"မျက်နှာပြင် လျှပ်တစ်ပြက်ပုံ မရိုက်နိုင်ပါ"</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ချွတ်ယွင်းမှုအစီရင်ခံချက် <xliff:g id="ID">#%d</xliff:g> အသေးစိတ်များ"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ဖိုင်အမည်"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"ခေါင်းစဉ်"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"အသေးစိတ် ဖော်ပြချက်"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"ချွတ်ယွင်းချက် ခေါင်းစဉ်"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"ချွတ်ယွင်းချက် အကျဉ်းချုပ်"</string>
+ <string name="save" msgid="4781509040564835759">"သိမ်းဆည်းပါ"</string>
</resources>
diff --git a/packages/Shell/res/values-nb/strings.xml b/packages/Shell/res/values-nb/strings.xml
index 328e8ae..aa86ae4 100644
--- a/packages/Shell/res/values-nb/strings.xml
+++ b/packages/Shell/res/values-nb/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skjermdumpen kunne ikke tas."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detaljer om feilrapporten <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Filnavn"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Tittel"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljert beskrivelse"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Navn på feil"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Oppsummering av feil"</string>
+ <string name="save" msgid="4781509040564835759">"Lagre"</string>
</resources>
diff --git a/packages/Shell/res/values-ne-rNP/strings.xml b/packages/Shell/res/values-ne-rNP/strings.xml
index 62bfead..43c2a5c 100644
--- a/packages/Shell/res/values-ne-rNP/strings.xml
+++ b/packages/Shell/res/values-ne-rNP/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रिनशट लिन सकिएन।"</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g>का विवरणहरू"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"फाइलको नाम"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"शीर्षक"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"विस्तृत विवरण"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"बगको शीर्षक"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"बगको सारांश"</string>
+ <string name="save" msgid="4781509040564835759">"सुरक्षित गर्नुहोस्"</string>
</resources>
diff --git a/packages/Shell/res/values-nl/strings.xml b/packages/Shell/res/values-nl/strings.xml
index 2f4b215..01fd577 100644
--- a/packages/Shell/res/values-nl/strings.xml
+++ b/packages/Shell/res/values-nl/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot kan niet worden gemaakt."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Details van bugrapport <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Bestandsnaam"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Gedetailleerde beschrijving"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Titel van bug"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Overzicht van bug"</string>
+ <string name="save" msgid="4781509040564835759">"Opslaan"</string>
</resources>
diff --git a/packages/Shell/res/values-pa-rIN/strings.xml b/packages/Shell/res/values-pa-rIN/strings.xml
index dc2277f..3494199 100644
--- a/packages/Shell/res/values-pa-rIN/strings.xml
+++ b/packages/Shell/res/values-pa-rIN/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨਹੀਂ ਲਿਆ ਜਾ ਸਕਿਆ।"</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ਬੱਗ ਰਿਪੋਰਟ <xliff:g id="ID">#%d</xliff:g> ਵੇਰਵੇ"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ਫ਼ਾਈਲ ਨਾਮ"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"ਸਿਰਲੇਖ"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"ਵਿਸਥਾਰ ਸਹਿਤ ਵਰਣਨ"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"ਬੱਗ ਸਿਰਲੇਖ"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"ਬੱਗ ਸਾਰਾਂਸ਼"</string>
+ <string name="save" msgid="4781509040564835759">"ਰੱਖਿਅਤ ਕਰੋ"</string>
</resources>
diff --git a/packages/Shell/res/values-pl/strings.xml b/packages/Shell/res/values-pl/strings.xml
index c585568..91934c9 100644
--- a/packages/Shell/res/values-pl/strings.xml
+++ b/packages/Shell/res/values-pl/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nie udało się zrobić zrzutu ekranu."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Szczegóły raportu o błędzie <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nazwa pliku"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Tytuł"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Szczegółowy opis"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Tytuł raportu o błędzie"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Podsumowanie raportu o błędzie"</string>
+ <string name="save" msgid="4781509040564835759">"Zapisz"</string>
</resources>
diff --git a/packages/Shell/res/values-pt-rBR/strings.xml b/packages/Shell/res/values-pt-rBR/strings.xml
index fc6e21c..41f4e24 100644
--- a/packages/Shell/res/values-pt-rBR/strings.xml
+++ b/packages/Shell/res/values-pt-rBR/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível fazer a captura de tela."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalhes do relatório de bugs <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nome do arquivo"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Título do bug"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Resumo do bug"</string>
+ <string name="save" msgid="4781509040564835759">"Salvar"</string>
</resources>
diff --git a/packages/Shell/res/values-pt-rPT/strings.xml b/packages/Shell/res/values-pt-rPT/strings.xml
index 252edb1..416db80 100644
--- a/packages/Shell/res/values-pt-rPT/strings.xml
+++ b/packages/Shell/res/values-pt-rPT/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível tirar a captura de ecrã."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalhes do relatório de erro <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nome do ficheiro"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Título do erro"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Resumo de erros"</string>
+ <string name="save" msgid="4781509040564835759">"Guardar"</string>
</resources>
diff --git a/packages/Shell/res/values-pt/strings.xml b/packages/Shell/res/values-pt/strings.xml
index fc6e21c..41f4e24 100644
--- a/packages/Shell/res/values-pt/strings.xml
+++ b/packages/Shell/res/values-pt/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível fazer a captura de tela."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalhes do relatório de bugs <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nome do arquivo"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Título do bug"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Resumo do bug"</string>
+ <string name="save" msgid="4781509040564835759">"Salvar"</string>
</resources>
diff --git a/packages/Shell/res/values-ro/strings.xml b/packages/Shell/res/values-ro/strings.xml
index d720417..4112e60 100644
--- a/packages/Shell/res/values-ro/strings.xml
+++ b/packages/Shell/res/values-ro/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Captura de ecran nu a putut fi făcută."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detaliile raportului de eroare <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Numele fișierului"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Titlu"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Descriere detaliată"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Titlul erorii"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Rezumat privind eroarea"</string>
+ <string name="save" msgid="4781509040564835759">"Salvați"</string>
</resources>
diff --git a/packages/Shell/res/values-ru/strings.xml b/packages/Shell/res/values-ru/strings.xml
index ed5ecaf..ffd2e66 100644
--- a/packages/Shell/res/values-ru/strings.xml
+++ b/packages/Shell/res/values-ru/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не удалось сделать скриншот"</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Данные отчета об ошибке <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Название файла"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Название"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Подробное описание"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Название ошибки"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Описание ошибки"</string>
+ <string name="save" msgid="4781509040564835759">"Сохранить"</string>
</resources>
diff --git a/packages/Shell/res/values-si-rLK/strings.xml b/packages/Shell/res/values-si-rLK/strings.xml
index cd8fba3..807ebb1 100644
--- a/packages/Shell/res/values-si-rLK/strings.xml
+++ b/packages/Shell/res/values-si-rLK/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"තිර රුවක් ගත නොහැකි විය."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"දෝෂ වාර්තා <xliff:g id="ID">#%d</xliff:g> විස්තර"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ගොනුවේ නම"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"මාතෘකාව"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"සවිස්තර විස්තරය"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"දෝෂ මාතෘකාව"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"දෝෂ සාරාංශය"</string>
+ <string name="save" msgid="4781509040564835759">"සුරකින්න"</string>
</resources>
diff --git a/packages/Shell/res/values-sk/strings.xml b/packages/Shell/res/values-sk/strings.xml
index 23e67f5..a62a6eb 100644
--- a/packages/Shell/res/values-sk/strings.xml
+++ b/packages/Shell/res/values-sk/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snímku obrazovky sa nepodarilo zaznamenať."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Podrobnosti hlásenia chyby <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Názov súboru"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Názov"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Podrobný popis"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Názov chyby"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Súhrn chyby"</string>
+ <string name="save" msgid="4781509040564835759">"Uložiť"</string>
</resources>
diff --git a/packages/Shell/res/values-sl/strings.xml b/packages/Shell/res/values-sl/strings.xml
index 519f3f2..6d1be5a 100644
--- a/packages/Shell/res/values-sl/strings.xml
+++ b/packages/Shell/res/values-sl/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Posnetka zaslon ni bilo mogoče ustvariti."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Podrobnosti poročila o napaki <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Ime datoteke"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Podroben opis"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Naslov poročila o napakah"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Povzetek poročila o napakah"</string>
+ <string name="save" msgid="4781509040564835759">"Shrani"</string>
</resources>
diff --git a/packages/Shell/res/values-sq-rAL/strings.xml b/packages/Shell/res/values-sq-rAL/strings.xml
index 5e3c706..ce990e9 100644
--- a/packages/Shell/res/values-sq-rAL/strings.xml
+++ b/packages/Shell/res/values-sq-rAL/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Pamja e ekranit nuk mund të realizohej."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detajet e raportit të defekteve në kod <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Emri i skedarit"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Titulli"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Përshkrimi i detajuar"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Titulli i defektit në kod"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Përmbledhja e defekteve në kod"</string>
+ <string name="save" msgid="4781509040564835759">"Ruaj"</string>
</resources>
diff --git a/packages/Shell/res/values-sr/strings.xml b/packages/Shell/res/values-sr/strings.xml
index 55119b6..0157a25 100644
--- a/packages/Shell/res/values-sr/strings.xml
+++ b/packages/Shell/res/values-sr/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Снимање екрана није успело."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Детаљи извештаја о грешци <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Назив датотеке"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Наслов"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Детаљни опис"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Наслов грешке"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Резиме грешке"</string>
+ <string name="save" msgid="4781509040564835759">"Сачувај"</string>
</resources>
diff --git a/packages/Shell/res/values-sv/strings.xml b/packages/Shell/res/values-sv/strings.xml
index 085f57e..88af0db 100644
--- a/packages/Shell/res/values-sv/strings.xml
+++ b/packages/Shell/res/values-sv/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Det gick inte att ta skrämdump."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Information för felrapporten <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Filnamn"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Namn"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljerad beskrivning"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Felets titel"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Sammanfattning av felet"</string>
+ <string name="save" msgid="4781509040564835759">"Spara"</string>
</resources>
diff --git a/packages/Shell/res/values-sw/strings.xml b/packages/Shell/res/values-sw/strings.xml
index c5a8ef1..01df55e 100644
--- a/packages/Shell/res/values-sw/strings.xml
+++ b/packages/Shell/res/values-sw/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Haikupiga picha ya skrini."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Maelezo ya ripoti ya hitilafu ya <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Jina la faili"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Kichwa"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Maelezo ya kina"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Jina la hitilafu"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Muhtasari wa hitilafu"</string>
+ <string name="save" msgid="4781509040564835759">"Hifadhi"</string>
</resources>
diff --git a/packages/Shell/res/values-ta-rIN/strings.xml b/packages/Shell/res/values-ta-rIN/strings.xml
index 7ef89e2..c14da56 100644
--- a/packages/Shell/res/values-ta-rIN/strings.xml
+++ b/packages/Shell/res/values-ta-rIN/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ஸ்கிரீன் ஷாட்டை எடுக்க முடியவில்லை."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"பிழை அறிக்கை <xliff:g id="ID">#%d</xliff:g> இன் விவரங்கள்"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"கோப்புப்பெயர்"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"தலைப்பு"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"விரிவான விளக்கம்"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"பிழை தலைப்பு"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"பிழை குறித்த சுருக்க விவரம்"</string>
+ <string name="save" msgid="4781509040564835759">"சேமி"</string>
</resources>
diff --git a/packages/Shell/res/values-te-rIN/strings.xml b/packages/Shell/res/values-te-rIN/strings.xml
index 6ba816b..3ed1f95 100644
--- a/packages/Shell/res/values-te-rIN/strings.xml
+++ b/packages/Shell/res/values-te-rIN/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"స్క్రీన్షాట్ను తీయడం సాధ్యపడలేదు."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> వివరాలు"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ఫైల్ పేరు"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"శీర్షిక"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"సమగ్ర వివరణ"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"బగ్ శీర్షిక"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"బగ్ సారాంశం"</string>
+ <string name="save" msgid="4781509040564835759">"సేవ్ చేయి"</string>
</resources>
diff --git a/packages/Shell/res/values-th/strings.xml b/packages/Shell/res/values-th/strings.xml
index d68ca26..f28bac6 100644
--- a/packages/Shell/res/values-th/strings.xml
+++ b/packages/Shell/res/values-th/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ไม่สามารถจับภาพหน้าจอได้"</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"รายละเอียดรายงานข้อบกพร่อง <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ชื่อไฟล์"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"ชื่อ"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"คำอธิบายโดยละเอียด"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"ชื่อข้อบกพร่อง"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"สรุปข้อบกพร่อง"</string>
+ <string name="save" msgid="4781509040564835759">"บันทึก"</string>
</resources>
diff --git a/packages/Shell/res/values-tl/strings.xml b/packages/Shell/res/values-tl/strings.xml
index 432eb90..d270401 100644
--- a/packages/Shell/res/values-tl/strings.xml
+++ b/packages/Shell/res/values-tl/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Hindi makunan ng screenshot."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Mga detalye ng ulat ng bug na <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Pamagat"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Detalyadong paglalarawan"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Pamagat ng bug"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Buod ng bug"</string>
+ <string name="save" msgid="4781509040564835759">"I-save"</string>
</resources>
diff --git a/packages/Shell/res/values-tr/strings.xml b/packages/Shell/res/values-tr/strings.xml
index dae377f..6da3490 100644
--- a/packages/Shell/res/values-tr/strings.xml
+++ b/packages/Shell/res/values-tr/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekran görüntüsü alınamadı."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Hata raporu (<xliff:g id="ID">#%d</xliff:g>) ayrıntıları"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Dosya adı"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Başlık"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Ayrıntılı açıklama"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Hata başlığı"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Hata özeti"</string>
+ <string name="save" msgid="4781509040564835759">"Kaydet"</string>
</resources>
diff --git a/packages/Shell/res/values-uk/strings.xml b/packages/Shell/res/values-uk/strings.xml
index 02eeb2f..00a7793 100644
--- a/packages/Shell/res/values-uk/strings.xml
+++ b/packages/Shell/res/values-uk/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не вдалося зробити знімок екрана."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Деталі повідомлення про помилку <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Назва файлу"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Назва"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Детальний опис"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Назва помилки"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Опис помилки"</string>
+ <string name="save" msgid="4781509040564835759">"Зберегти"</string>
</resources>
diff --git a/packages/Shell/res/values-ur-rPK/strings.xml b/packages/Shell/res/values-ur-rPK/strings.xml
index 23cada6..abf6940 100644
--- a/packages/Shell/res/values-ur-rPK/strings.xml
+++ b/packages/Shell/res/values-ur-rPK/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"سکرین شاٹ نہیں لیا جا سکا۔"</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"بگ رپورٹ <xliff:g id="ID">#%d</xliff:g> کی تفصیلات"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"فائل کا نام"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"عنوان"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"تفصیلی وضاحت"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"بَگ کا عنوان"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"بَگ کا خلاصہ"</string>
+ <string name="save" msgid="4781509040564835759">"محفوظ کریں"</string>
</resources>
diff --git a/packages/Shell/res/values-uz-rUZ/strings.xml b/packages/Shell/res/values-uz-rUZ/strings.xml
index 39703a2..7782b42 100644
--- a/packages/Shell/res/values-uz-rUZ/strings.xml
+++ b/packages/Shell/res/values-uz-rUZ/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skrinshot olib bo‘lmadi."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Xatoliklar hisoboti (<xliff:g id="ID">#%d</xliff:g>) tafsilotlari"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Fayl nomi"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Nomi"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Batafsil ta’rif"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Xatolik nomi"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Xatolik ta’rifi"</string>
+ <string name="save" msgid="4781509040564835759">"Saqlash"</string>
</resources>
diff --git a/packages/Shell/res/values-vi/strings.xml b/packages/Shell/res/values-vi/strings.xml
index 16ffaff..27a9c7f 100644
--- a/packages/Shell/res/values-vi/strings.xml
+++ b/packages/Shell/res/values-vi/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Không thể chụp ảnh màn hình."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Chi tiết báo cáo lỗi <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Tên tệp"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Tiêu đề"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Mô tả chi tiết"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Tiêu đề lỗi"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Tóm tắt lỗi"</string>
+ <string name="save" msgid="4781509040564835759">"Lưu"</string>
</resources>
diff --git a/packages/Shell/res/values-zh-rCN/strings.xml b/packages/Shell/res/values-zh-rCN/strings.xml
index 382478e..65cfbbc 100644
--- a/packages/Shell/res/values-zh-rCN/strings.xml
+++ b/packages/Shell/res/values-zh-rCN/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"无法截图。"</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"错误报告 <xliff:g id="ID">#%d</xliff:g> 详情"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"文件名"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"标题"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"详细说明"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"错误标题"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"错误摘要"</string>
+ <string name="save" msgid="4781509040564835759">"保存"</string>
</resources>
diff --git a/packages/Shell/res/values-zh-rHK/strings.xml b/packages/Shell/res/values-zh-rHK/strings.xml
index 04b5e48..34a849e 100644
--- a/packages/Shell/res/values-zh-rHK/strings.xml
+++ b/packages/Shell/res/values-zh-rHK/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"無法擷取螢幕畫面。"</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"錯誤報告 <xliff:g id="ID">#%d</xliff:g> 的詳情"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"檔案名稱"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"標題"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"詳細說明"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"錯誤標題"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"錯誤摘要"</string>
+ <string name="save" msgid="4781509040564835759">"儲存"</string>
</resources>
diff --git a/packages/Shell/res/values-zh-rTW/strings.xml b/packages/Shell/res/values-zh-rTW/strings.xml
index 7a1ab77..fff73bb 100644
--- a/packages/Shell/res/values-zh-rTW/strings.xml
+++ b/packages/Shell/res/values-zh-rTW/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"無法拍攝螢幕擷取畫面。"</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"錯誤報告 <xliff:g id="ID">#%d</xliff:g> 的詳細資料"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"檔案名稱"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"標題"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"詳細說明"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"錯誤標題"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"錯誤摘要"</string>
+ <string name="save" msgid="4781509040564835759">"儲存"</string>
</resources>
diff --git a/packages/Shell/res/values-zu/strings.xml b/packages/Shell/res/values-zu/strings.xml
index 29b7dd83..868de3e 100644
--- a/packages/Shell/res/values-zu/strings.xml
+++ b/packages/Shell/res/values-zu/strings.xml
@@ -34,6 +34,7 @@
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Isithombe-skrini asikwazanga ukuthathwa."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Imininingwane yombiko wesiphazamisi ongu-<xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Igama lefayela"</string>
- <string name="bugreport_info_title" msgid="5599558206004371052">"Isihloko"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Incazelo enemininingwane"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"Isihloko sesiphazamisi"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"Isifinyezo sesiphazamisi"</string>
+ <string name="save" msgid="4781509040564835759">"Londoloza"</string>
</resources>
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 0b52588..0fad113 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -121,8 +121,6 @@
static final String INTENT_BUGREPORT_FINISHED = "android.intent.action.BUGREPORT_FINISHED";
static final String INTENT_REMOTE_BUGREPORT_FINISHED =
"android.intent.action.REMOTE_BUGREPORT_FINISHED";
- static final String INTENT_REMOTE_BUGREPORT_DISPATCH =
- "android.intent.action.REMOTE_BUGREPORT_DISPATCH";
// Internal intents used on notification actions.
static final String INTENT_BUGREPORT_CANCEL = "android.intent.action.BUGREPORT_CANCEL";
diff --git a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
index 814aa8c..49759c5 100644
--- a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
+++ b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
@@ -56,7 +56,7 @@
final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
final RowBuilder row = result.newRow();
row.add(Root.COLUMN_ROOT_ID, DOC_ID_ROOT);
- row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED);
+ row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY);
row.add(Root.COLUMN_ICON, android.R.mipmap.sym_def_app_icon);
row.add(Root.COLUMN_TITLE, getContext().getString(R.string.bugreport_storage_title));
row.add(Root.COLUMN_DOCUMENT_ID, DOC_ID_ROOT);
diff --git a/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java b/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java
index be54b43..634c3b4 100644
--- a/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java
@@ -18,13 +18,13 @@
import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
import static com.android.shell.BugreportProgressService.INTENT_REMOTE_BUGREPORT_FINISHED;
-import static com.android.shell.BugreportProgressService.INTENT_REMOTE_BUGREPORT_DISPATCH;
import static com.android.shell.BugreportProgressService.getFileExtra;
import static com.android.shell.BugreportProgressService.getUri;
import static com.android.shell.BugreportReceiver.cleanupOldFiles;
import java.io.File;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -41,8 +41,6 @@
public class RemoteBugreportReceiver extends BroadcastReceiver {
private static final String BUGREPORT_MIMETYPE = "application/vnd.android.bugreport";
- private static final String EXTRA_REMOTE_BUGREPORT_HASH =
- "android.intent.extra.REMOTE_BUGREPORT_HASH";
/** Always keep just the last remote bugreport's files around. */
private static final int REMOTE_BUGREPORT_FILES_AMOUNT = 3;
@@ -57,11 +55,12 @@
final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
final Uri bugreportUri = getUri(context, bugreportFile);
- final String bugreportHash = intent.getStringExtra(EXTRA_REMOTE_BUGREPORT_HASH);
+ final String bugreportHash = intent.getStringExtra(
+ DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH);
- final Intent newIntent = new Intent(INTENT_REMOTE_BUGREPORT_DISPATCH);
+ final Intent newIntent = new Intent(DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH);
newIntent.setDataAndType(bugreportUri, BUGREPORT_MIMETYPE);
- newIntent.putExtra(EXTRA_REMOTE_BUGREPORT_HASH, bugreportHash);
+ newIntent.putExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH, bugreportHash);
context.sendBroadcastAsUser(newIntent, UserHandle.SYSTEM,
android.Manifest.permission.DUMP);
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index b5b7bcd7..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/drawable/tv_pip_overlay_background.xml b/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml
new file mode 100644
index 0000000..e247dec
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml
@@ -0,0 +1,23 @@
+<!--
+ 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="#B2000000"
+ android:endColor="#00000000"
+ android:angle="90"/>
+</shape>
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_customize_panel.xml b/packages/SystemUI/res/layout/qs_customize_panel.xml
index 582ad48..0491ea0 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel.xml
@@ -14,10 +14,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
+<!-- Height is 0 because it will be managed by the QSContainer manually -->
<com.android.systemui.qs.customize.QSCustomizer
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="0dp"
android:orientation="vertical"
android:background="@drawable/qs_customizer_background"
android:gravity="center_horizontal">
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 994d3c9..ef15195 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -34,4 +34,7 @@
<include android:id="@+id/qs_detail" layout="@layout/qs_detail" />
+ <include android:id="@+id/qs_customize" layout="@layout/qs_customize_panel"
+ android:visibility="gone" />
+
</com.android.systemui.qs.QSContainer>
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/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 656941f..ccefb5f 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -43,8 +43,10 @@
android:id="@+id/qs_density_container"
android:layout="@layout/qs_panel"
android:layout_width="@dimen/notification_panel_width"
- android:layout_height="wrap_content"
- android:layout_gravity="@integer/notification_panel_layout_gravity" />
+ android:layout_height="match_parent"
+ android:layout_gravity="@integer/notification_panel_layout_gravity"
+ android:clipToPadding="false"
+ android:clipChildren="false" />
<com.android.systemui.statusbar.stack.NotificationStackScrollLayout
android:id="@+id/notification_stack_scroller"
diff --git a/packages/SystemUI/res/layout/tv_pip_overlay.xml b/packages/SystemUI/res/layout/tv_pip_overlay.xml
index ebd362c..40c6fa1 100644
--- a/packages/SystemUI/res/layout/tv_pip_overlay.xml
+++ b/packages/SystemUI/res/layout/tv_pip_overlay.xml
@@ -24,12 +24,13 @@
<TextView
android:id="@+id/guide_overlay"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="32dp"
android:layout_alignParentBottom="true"
- android:padding="3dp"
- android:textSize="13sp"
- android:textColor="#111111"
- android:background="#99EEEEEE"
+ android:textSize="14sp"
+ android:textColor="#EEEEEE"
+ android:fontFamily="sans-serif"
+ android:background="@drawable/tv_pip_overlay_background"
+ android:gravity="center"
android:text="@string/pip_hold_home" />
<LinearLayout
android:id="@+id/guide_buttons"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 61d4f14..30d9ed7 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Meer tyd."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Minder tyd."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Flitslig af."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Flitslig is nie beskikbaar nie."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Flitslig aan."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Flitslig afgeskakel."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Flitslig aangeskakel."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Skakel Bluetooth aan?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Jy moet Bluetooth aanskakel om jou sleutelbord aan jou tablet te koppel."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Skakel aan"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Wys kennisgewings sonder klank"</string>
+ <string name="block" msgid="2734508760962682611">"Blokkeer alle kennisgewings"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Moenie stilmaak nie"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Moenie stilmaak of blokkeer nie"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Wys volledige belangrikheidinstellings"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Geblokkeer"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Onbelangrik"</string>
<string name="low_importance" msgid="4109929986107147930">"Min belang"</string>
<string name="default_importance" msgid="8192107689995742653">"Normale belang"</string>
<string name="high_importance" msgid="1527066195614050263">"Groot belang"</string>
<string name="max_importance" msgid="5089005872719563894">"Dringende belang"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Moet nooit hierdie kennisgewings wys nie"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Wys sonder klank aan die onderkant van die kennisgewinglys"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Wys hierdie kennisgewings sonder klank"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Laat hierdie kennisgewing toe om geluide te maak"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Verskyn vlugtig op die skerm en laat klank toe"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Wys boaan die kennisgewingslys, verskyn vlugtig op die skerm en laat klank toe"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Meer instellings"</string>
<string name="notification_done" msgid="5279426047273930175">"Klaar"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Kleur en voorkoms"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Wys persentasie wanneer gelaai word (verstek)"</item>
<item msgid="3327323682209964956">"Moenie hierdie ikoon wys nie"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Ander"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Skermverdeler"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Skuif af"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Skuif op"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 6d70c8a..9692ae8 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"ተጨማሪ ጊዜ።"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"ያነሰ ጊዜ።"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"የባትሪ ብርሃን ጠፍቷል።"</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"የባትሪ ብርሃን አይገኝም።"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"የባትሪ ብርሃን በርቷል።"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"የባትሪ ብርሃን ጠፍቷል።"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"የባትሪ ብርሃን በርቷል።"</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ብሉቱዝ ይብራ?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"የቁልፍ ሰሌዳዎን ከእርስዎ ጡባዊ ጋር ለማገናኘት በመጀመሪያ ብሉቱዝን ማብራት አለብዎት።"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"አብራ"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"ማሳወቂያዎችን በጸጥታ አሳይ"</string>
+ <string name="block" msgid="2734508760962682611">"ሁሉንም ማሳወቂያዎች አግድ"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"ድምፅ አትዝጋ"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"ድምፅ አትዝጋ ወይም አታግድ"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"ሙሉ የአስፈላጊነት ቅንብሮችን አሳይ"</string>
<string name="blocked_importance" msgid="5198578988978234161">"የታገዱ"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"አነስተኛ አስፈላጊነት"</string>
<string name="low_importance" msgid="4109929986107147930">"ዝቅተኛ አስፈላጊነት"</string>
<string name="default_importance" msgid="8192107689995742653">"መደበኛ አስፈላጊነት"</string>
<string name="high_importance" msgid="1527066195614050263">"ከፍተኛ አስፈላጊነት"</string>
<string name="max_importance" msgid="5089005872719563894">"አስቸኳይ አስፈላጊነት"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"እነዚህን ማሳወቂያዎች በጭራሽ አታሳይ"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"በማሳወቂያ ዝርዝሩ ታችኛውን ክፍል ላይ በጸጥታ አሳይ"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"እነዚህን ማሳወቂያዎች በጸጥታ አሳይ"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"እነዚህ ማሳወቂያዎች ድምፆችን እንዲፈጥሩ ፍቀድ"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"ወደ ማያ ገጹ አስገባና ድምፅ ፍቀድ"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"በማሳወቂያዎች ዝርዝር አናት ላይ አሳይ፣ ወደ ማያ ገጹ አሳይና ድምፅ ፍቀድ"</string>
<string name="notification_more_settings" msgid="816306283396553571">"ተጨማሪ ቅንብሮች"</string>
<string name="notification_done" msgid="5279426047273930175">"ተከናውኗል"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"ቀለም እና መልክ"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"የባትሪ ኃይል በሚሞላበት ጊዜ መቶኛ አሳይ (ነባሪ)"</item>
<item msgid="3327323682209964956">"ይህን አዶ አታሳይ"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"ሌላ"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"የተከፈለ የማያ ገጽ ከፋይ"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"ወደ ታች ሂድ"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ወደ ላይ ሂድ"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 2e4724b..3edc805 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -208,8 +208,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Više vremena."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Manje vremena."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Baterijska lampa je isključena."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lampa nije dostupna."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Baterijska lampa je uključena."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Baterijska lampa je isključena."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Baterijska lampa je uključena."</string>
@@ -457,34 +456,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite li da uključite Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Da biste povezali tastaturu sa tabletom, prvo morate da uključite Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Uključi"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Prikazuj obaveštenja bez zvuka"</string>
+ <string name="block" msgid="2734508760962682611">"Blokiraj sva obaveštenja"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Ne isključuj zvuk"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Ne isključuju zvuk niti blokiraj"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Prikaži kompletna podešavanja važnosti"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Blokirana"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Veoma mala važnost"</string>
<string name="low_importance" msgid="4109929986107147930">"Mala važnost"</string>
<string name="default_importance" msgid="8192107689995742653">"Uobičajena važnost"</string>
<string name="high_importance" msgid="1527066195614050263">"Velika važnost"</string>
<string name="max_importance" msgid="5089005872719563894">"Važnost: hitno"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Ova obaveštenja se nikada ne prikazuju"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Prikazuju se u dnu liste obaveštenja bez zvuka"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Ova obaveštenja se prikazuju bez zvuka"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Dozvolite da ova obaveštenja emituju zvuk"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Nakratko se prikazuju na ekranu i emituju zvuk"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Prikazuju se u vrhu liste obaveštenja, nakratko se prikazuju na ekranu i emituju zvuk"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Još podešavanja"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Boja i izgled"</string>
@@ -557,8 +545,7 @@
<item msgid="2139628951880142927">"Prikaži procenat tokom punjenja (podrazumevano)"</item>
<item msgid="3327323682209964956">"Ne prikazuj ovu ikonu"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Drugo"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Razdelnik podeljenog ekrana"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pomeri nadole"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pomeri nagore"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index c97a6a5..84757b7 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Повече време."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"По-малко време."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Фенерчето е изключено."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Няма достъп до фенерчето."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Фенерчето е включено."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Фенерчето е изключено."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Фенерчето е включено."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Да се включи ли Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"За да свържете клавиатурата с таблета си, първо трябва да включите Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Включване"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Показване на известията без звуков сигнал"</string>
+ <string name="block" msgid="2734508760962682611">"Блокиране на всички известия"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Без заглушаване на звуковите сигнали"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Без заглушаване на звуковите сигнали или блокиране"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Показване на пълните настройки за важността"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Блокирано"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Минимална важност"</string>
<string name="low_importance" msgid="4109929986107147930">"Малка важност"</string>
<string name="default_importance" msgid="8192107689995742653">"Нормална важност"</string>
<string name="high_importance" msgid="1527066195614050263">"Голяма важност"</string>
<string name="max_importance" msgid="5089005872719563894">"Неотложна важност"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Тези известия не се показват"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Показване без звуков сигнал най-долу в списъка с известия"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Показване на тези известия без звуков сигнал"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Разрешаване при тези известия да се издава звуков сигнал"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Показване на екрана и разрешаване на звуков сигнал"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Показване най-горе в списъка с известия, както и на екрана и разрешаване на звуков сигнал"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Още настройки"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Цвят и облик"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Процентът да се показва при зареждане (по подразбиране)"</item>
<item msgid="3327323682209964956">"Тази икона да не се показва"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Друго"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Разделител в режима за разделен екран"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Преместване надолу"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Преместване нагоре"</string>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index f59f3ca..18f37e6 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -548,6 +548,6 @@
<string name="accessibility_divider" msgid="5903423481953635044">"বিভক্ত-স্ক্রীন বিভাজক"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"নীচে সরান"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"উপরে সরান"</string>
- <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"বামে সরান"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"বাঁয়ে সরান"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ডানে সরান"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
index 865b1ad..3a7c6cd 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
@@ -208,8 +208,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Više vremena."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Manje vremena."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Svjetiljka isključena."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Svjetiljka nije dostupna."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Svjetiljka uključena."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Svjetiljka je isključena."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Svjetiljka je uključena."</string>
@@ -457,34 +456,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Želiti li uključiti Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Da povežete tastaturu sa tabletom, prvo morate uključiti Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Uključi"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Nečujno prikaži obavijesti"</string>
+ <string name="block" msgid="2734508760962682611">"Blokiraj sva obavještenja"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Nemoj utišati"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Nemoj utišati ili blokirati"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Prikaži kompletne postavke za određivanje značaja"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Blokirano"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Minimalni značaj"</string>
<string name="low_importance" msgid="4109929986107147930">"Mali značaj"</string>
<string name="default_importance" msgid="8192107689995742653">"Normalan značaj"</string>
<string name="high_importance" msgid="1527066195614050263">"Visok značaj"</string>
<string name="max_importance" msgid="5089005872719563894">"Hitan značaj"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Nikada ne prikazuj ova obavještenja"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Nečujno prikaži na dnu spiska obavještenja"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Nečujno prikaži ova obavještenja"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Dozvolite zvuk na ovim obavještenjima"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Kratko prikaži na ekranu i dozvoli zvuk"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Prikaži na vrhu liste obavještenja, kratko prikaži na ekranu i dozvoli zvuk"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Boja i izgled"</string>
@@ -557,8 +545,7 @@
<item msgid="2139628951880142927">"Pokaži postotak u toku punjenja (zadano)"</item>
<item msgid="3327323682209964956">"Ne prikazuj ovu ikonu"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Ostalo"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Razdjelnik ekrana"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pomjeri dolje"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pomjeri gore"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 3243f74..f8224ac 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Més temps"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menys temps"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Llanterna desactivada"</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"La llanterna no està disponible."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Llanterna activada"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Llanterna desactivada."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Llanterna activada."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vols activar el Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connectar el teclat amb la tauleta, primer has d\'activar el Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activa"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Mostra les notificacions de manera silenciosa"</string>
+ <string name="block" msgid="2734508760962682611">"Bloqueja totes les notificacions"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"No silenciïs"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"No silenciïs ni bloquegis"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostra la configuració completa per a la importància"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Bloquejades"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Importància mínima"</string>
<string name="low_importance" msgid="4109929986107147930">"Importància baixa"</string>
<string name="default_importance" msgid="8192107689995742653">"Importància normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Importància alta"</string>
<string name="max_importance" msgid="5089005872719563894">"Importància urgent"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"No mostris mai aquestes notificacions"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Les notificacions es mostren de manera silenciosa al capdavall de la llista"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Mostra aquestes notificacions de manera silenciosa"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Permet que aquestes notificacions emetin sons"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Les notificacions apareixen a la pantalla i poden emetre sons"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Les notificacions es mostren al capdamunt de la llista, apareixen a la pantalla i poden emetre sons"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Més opcions"</string>
<string name="notification_done" msgid="5279426047273930175">"Fet"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Color i aparença"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Mostra el percentatge quan es carregui (opció predeterminada)"</item>
<item msgid="3327323682209964956">"No mostris aquesta icona"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Altres"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Divisor de pantalles"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mou avall"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mou amunt"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index b5b4037..48c9c55 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -209,8 +209,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Delší doba"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kratší doba"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Svítilna je vypnutá."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Svítilna není k dispozici."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Svítilna je zapnutá."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Svítilna je vypnutá."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Svítilna je zapnutá."</string>
@@ -458,34 +457,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnout Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Chcete-li klávesnici připojit k tabletu, nejdříve musíte zapnout Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Zapnout"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Zobrazovat oznámení tiše"</string>
+ <string name="block" msgid="2734508760962682611">"Blokovat všechna oznámení"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Bez ztlumení"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Bez ztlumení a blokování"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Zobrazit všechna nastavení důležitosti"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Blokováno"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Minimální důležitost"</string>
<string name="low_importance" msgid="4109929986107147930">"Nízká důležitost"</string>
<string name="default_importance" msgid="8192107689995742653">"Normální důležitost"</string>
<string name="high_importance" msgid="1527066195614050263">"Vysoká důležitost"</string>
<string name="max_importance" msgid="5089005872719563894">"Urgentní důležitost"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Tato oznámení nikdy nezobrazovat"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Tato oznámení zobrazovat na konci seznamu bez zvukového upozornění"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Tato oznámení zobrazovat bez zvukového upozornění"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Povolit těmto oznámením vydávat zvuky"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Tato oznámení zobrazovat přímo na obrazovce a upozornit na ně zvukem"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Tato oznámení zobrazovat na začátku seznamu, zobrazit přímo na obrazovce a upozornit na ně zvukem"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Další nastavení"</string>
<string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Barva a vzhled"</string>
@@ -558,8 +546,7 @@
<item msgid="2139628951880142927">"Zobrazovat procento při nabíjení (výchozí nastavení)"</item>
<item msgid="3327323682209964956">"Tuto ikonu nezobrazovat"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Jiné"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Čára rozdělující obrazovku"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Přesunout dolů"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Přesunout nahoru"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index f4987d7..50d01ea 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mere tid."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mindre tid."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lommelygten er slået fra."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lommelygten er ikke tilgængelig."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lommelygten er slået til."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lommelygten er slået fra."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lommelygten er slået til."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå Bluetooth til?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Bluetooth skal være slået til, før du kan knytte dit tastatur til din tablet."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Slå til"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Vis underretninger lydløst"</string>
+ <string name="block" msgid="2734508760962682611">"Bloker alle underretninger"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Skal ikke sættes på lydløs"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Skal ikke sættes på lydløs eller blokeres"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Vis alle indstillinger for vigtighed"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Blokeret"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Min vigtighed"</string>
<string name="low_importance" msgid="4109929986107147930">"Lille vigtighed"</string>
<string name="default_importance" msgid="8192107689995742653">"Normal vigtighed"</string>
<string name="high_importance" msgid="1527066195614050263">"Stor vigtighed"</string>
<string name="max_importance" msgid="5089005872719563894">"Presserende vigtighed"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Vis aldrig disse underretninger"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Vis lydløst nederst på listen over underretninger"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Vis disse underretninger lydløst"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Giv disse underretninger tilladelse til at give lyd"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Vis på skærmen, og tillad lyd"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Vis øverst på listen over underretninger, vis på skærmen, og tillad lyd"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
<string name="notification_done" msgid="5279426047273930175">"Færdig"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Farve og udseende"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Vis procent ved opladning (standard)"</item>
<item msgid="3327323682209964956">"Vis ikke dette ikon"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Andet"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Adskiller til delt skærm"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Flyt ned"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Flyt op"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index ac0adbb..fd8cf89 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mehr Zeit"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Weniger Zeit"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Taschenlampe deaktiviert"</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Taschenlampe nicht verfügbar."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Taschenlampe aktiviert"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Die Taschenlampe ist deaktiviert."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Die Taschenlampe ist aktiviert."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth aktivieren?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Zum Verbinden von Tastatur und Tablet muss Bluetooth aktiviert sein."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivieren"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Benachrichtigungen ohne Ton anzeigen"</string>
+ <string name="block" msgid="2734508760962682611">"Alle Benachrichtigungen blockieren"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Nicht stummschalten"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Nicht stummschalten oder blockieren"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Vollständige Wichtigkeitseinstellungen anzeigen"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Blockiert"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Minimum-Wichtigkeit"</string>
<string name="low_importance" msgid="4109929986107147930">"Geringe Wichtigkeit"</string>
<string name="default_importance" msgid="8192107689995742653">"Reguläre Wichtigkeit"</string>
<string name="high_importance" msgid="1527066195614050263">"Hohe Wichtigkeit"</string>
<string name="max_importance" msgid="5089005872719563894">"Sehr hohe Wichtigkeit"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Diese Benachrichtigungen niemals anzeigen"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Ohne Ton am Ende der Benachrichtigungsliste anzeigen"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Diese Benachrichtigungen ohne Ton anzeigen"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Für diese Benachrichtigungen Ton zulassen"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Auf dem Display einblenden und Ton zulassen"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Ganz oben in der Benachrichtigungsliste anzeigen, auf dem Display einblenden und Ton zulassen"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Weitere Einstellungen"</string>
<string name="notification_done" msgid="5279426047273930175">"Fertig"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Farbe und Darstellung"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Prozentwert beim Laden anzeigen (Standardeinstellung)"</item>
<item msgid="3327323682209964956">"Dieses Symbol nicht anzeigen"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Sonstiges"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Bildschirmteiler"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Nach unten verschieben"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Nach oben verschieben"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 754c92e..b5f55d9 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Περισσότερη ώρα."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Λιγότερη ώρα."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Ανενεργός φακός."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Ο φακός δεν είναι διαθέσιμος."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Ενεργός φακός."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Ο φακός απενεργοποιήθηκε."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Ο φακός ενεργοποιήθηκε."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Ενεργοποίηση Bluetooth;"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Για να συνδέσετε το πληκτρολόγιο με το tablet σας, θα πρέπει πρώτα να ενεργοποιήσετε το Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ενεργοποίηση"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Εμφάνιση ειδοποιήσεων χωρίς ήχο"</string>
+ <string name="block" msgid="2734508760962682611">"Αποκλεισμός όλων των ειδοποιήσεων"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Χωρίς σίγαση"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Χωρίς σίγαση ή αποκλεισμό"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Εμφάνιση όλων των ρυθμίσεων βαρύτητας"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Αποκλεισμένες"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Ελάχιστη βαρύτητα"</string>
<string name="low_importance" msgid="4109929986107147930">"Μικρής βαρύτητας"</string>
<string name="default_importance" msgid="8192107689995742653">"Κανονικής βαρύτητας"</string>
<string name="high_importance" msgid="1527066195614050263">"Μεγάλης βαρύτητας"</string>
<string name="max_importance" msgid="5089005872719563894">"Επείγουσες"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Να μην εμφανίζονται ποτέ αυτές οι ειδοποιήσεις"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Να εμφανίζονται στο κάτω μέρος της λίστας ειδοποιήσεων χωρίς ήχο"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Να εμφανίζονται αυτές οι ειδοποιήσεις χωρίς ήχο"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Να επιτρέπονται οι ήχοι από αυτές τις ειδοποιήσεις"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Να προβάλλονται στην οθόνη και να επιτρέπεται ο ήχος"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Να εμφανίζονται στην κορυφή της λίστας ειδοποιήσεων, να προβάλλονται στην οθόνη και να επιτρέπεται ο ήχος"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Περισσότερες ρυθμίσεις"</string>
<string name="notification_done" msgid="5279426047273930175">"Τέλος"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Χρώμα και εμφάνιση"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Να εμφανίζεται ποσοστό κατά τη φόρτιση (προεπιλογή)"</item>
<item msgid="3327323682209964956">"Να μην εμφανίζεται αυτό το εικονίδιο"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Άλλο"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Διαχωριστικό οθόνης"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Μετακίνηση προς τα κάτω"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Μετακίνηση προς τα επάνω"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index f3c21df..856c1c1 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Más tiempo"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tiempo"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Linterna desactivada"</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"La linterna no está disponible."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Linterna activada"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Linterna desactivada"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Linterna activada"</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar el teclado con la tablet, primero debes activar Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Mostrar notificaciones de manera silenciosa"</string>
+ <string name="block" msgid="2734508760962682611">"Bloquear todas las notificaciones"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"No silenciar"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"No silenciar ni bloquear"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar configuración de importancia"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Bloqueada"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Importancia mínima"</string>
<string name="low_importance" msgid="4109929986107147930">"Poca importancia"</string>
<string name="default_importance" msgid="8192107689995742653">"Importancia normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Importancia alta"</string>
<string name="max_importance" msgid="5089005872719563894">"Urgente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"No mostrar nunca estas notificaciones"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar en la parte inferior de la lista de notificaciones sin emitir sonido"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar estas notificaciones de manera silenciosa"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que estas notificaciones emitan sonidos"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Ver en la pantalla y permitir sonidos"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar en la parte superior de la lista de notificaciones, ver en la pantalla y permitir sonidos"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Más opciones de configuración"</string>
<string name="notification_done" msgid="5279426047273930175">"Listo"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Color y apariencia"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Mostrar el porcentaje durante la carga (predeterminado)"</item>
<item msgid="3327323682209964956">"No mostrar este ícono"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Otros"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Divisor de pantalla dividida"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mover hacia abajo"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover hacia arriba"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index bd9cc00..4092994 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Más tiempo."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tiempo."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Linterna desactivada."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"La linterna no está disponible."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Linterna activada."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Linterna desactivada."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Linterna activada."</string>
@@ -304,8 +303,7 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fijación de pantalla"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"No se ha podido iniciar <xliff:g id="APP">%s</xliff:g>."</string>
- <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
- <skip />
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"La aplicación <xliff:g id="APP">%s</xliff:g> se ha inhabilitado en modo seguro."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Historial"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Borrar"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Esta aplicación no admite el modo multiventana."</string>
@@ -457,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para poder conectar tu teclado a tu tablet, debes activar el Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Mostrar notificaciones de forma silenciosa"</string>
+ <string name="block" msgid="2734508760962682611">"Bloquear todas las notificaciones"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"No silenciar"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"No silenciar ni bloquear"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar ajustes de importancia por completo"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Bloqueado"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Importancia mínima"</string>
<string name="low_importance" msgid="4109929986107147930">"Poco importante"</string>
<string name="default_importance" msgid="8192107689995742653">"Importancia normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Muy importante"</string>
<string name="max_importance" msgid="5089005872719563894">"Urgente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"No mostrar estas notificaciones"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar en la parte inferior de la lista de notificaciones de forma silenciosa"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar estas notificaciones de forma silenciosa"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que estas notificaciones reproduzcan sonidos"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Mostrar en la pantalla y permitir sonido"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar en la parte superior de la lista de notificaciones, mostrar en la pantalla y permitir sonido"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Más ajustes"</string>
<string name="notification_done" msgid="5279426047273930175">"Listo"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Color y aspecto"</string>
@@ -557,8 +544,7 @@
<item msgid="2139628951880142927">"Mostrar porcentaje durante la carga (predeterminado)"</item>
<item msgid="3327323682209964956">"No mostrar este icono"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Otros"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Dividir la pantalla"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Bajar"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Subir"</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index a245bf7..29e3da8 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Denbora gehiago."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Denbora gutxiago."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Flasha desaktibatuta dago."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Linterna ez dago erabilgarri."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Flasha aktibatuta dago."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Flasha desaktibatu egin da."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Flasha aktibatu egin da."</string>
@@ -309,9 +308,9 @@
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Garbitu"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Aplikazioak ez du onartzen leiho bat baino gehiago erabiltzea"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikazioak ez du onartzen leiho bat baino gehiago erabiltzea"</string>
- <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Banaketa horizontala"</string>
- <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Banaketa bertikala"</string>
- <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Banaketa pertsonalizatua"</string>
+ <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Zatitze horizontala"</string>
+ <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Zatitze bertikala"</string>
+ <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Zatitze pertsonalizatua"</string>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Kargatuta"</string>
<string name="expanded_header_battery_charging" msgid="205623198487189724">"Kargatzen"</string>
<string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> falta zaizkio guztiz kargatzeko"</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth eginbidea aktibatu nahi duzu?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Teklatua tabletara konektatzeko, Bluetooth eginbidea aktibatu behar duzu."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktibatu"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Erakutsi jakinarazpenak soinurik egin gabe"</string>
+ <string name="block" msgid="2734508760962682611">"Blokeatu jakinarazpen guztiak"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Ez isilarazi"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Ez isilarazi edo blokeatu"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Erakutsi garrantzi handiko jakinarazpenen ezarpenak"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Blokeatuta"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Gutxieneko garrantzia"</string>
<string name="low_importance" msgid="4109929986107147930">"Garrantzi txikia"</string>
<string name="default_importance" msgid="8192107689995742653">"Garrantzi normala"</string>
<string name="high_importance" msgid="1527066195614050263">"Garrantzi handia"</string>
<string name="max_importance" msgid="5089005872719563894">"Premiazkoa"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Ez erakutsi jakinarazpen hauek inoiz"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Erakutsi jakinarazpen hauek zerrendaren behealdean, baina soinurik egin gabe"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Erakutsi jakinarazpen hauek, baina soinurik egin gabe"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Egin soinua jakinarazpen hauek jasotzean"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Agerrarazi jakinarazpen hauek pantailan eta egin soinua"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Erakutsi jakinarazpen hauek zerrendaren goialdean, agerrarazi pantailan eta egin soinua"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Ezarpen gehiago"</string>
<string name="notification_done" msgid="5279426047273930175">"Eginda"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Kolorea eta itxura"</string>
@@ -497,7 +485,7 @@
<string name="use_dark_theme" msgid="2900938704964299312">"Erabili gai iluna Android sistema eragilean"</string>
<string name="adjust_tint" msgid="3398569573231409878">"Doitu kolorea"</string>
<string name="adjust_brightness" msgid="980039329808178246">"Doitu distira"</string>
- <string name="night_mode_disclaimer" msgid="598914896926759578">"Gai iluna Android sistema eragileko eremu nagusietan aplikatzen da. Normalean gai argian bistaratzen dira eremu horiek, adibidez, Ezarpenak atala."</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Gai iluna Android sistema eragileko eremu nagusietan aplikatzen da. Normalean gai argian bistaratzen dira eremu horiek, adibidez, Ezarpenak atalean."</string>
<string name="color_apply" msgid="9212602012641034283">"Aplikatu"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Berretsi ezarpenak"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Baliteke gailua kolore-ezarpen batzuekin ezin erabili izatea. Kolore-ezarpenak berresteko, sakatu Ados. Bestela, hamar segundoren buruan berrezarriko dira ezarpenak."</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Erakutsi ehunekoa kargatu bitartean (balio lehenetsia)"</item>
<item msgid="3327323682209964956">"Ez erakutsi ikonoa"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Beste bat"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Pantaila-zatitzailea"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Eraman behera"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Eraman gora"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 2243191..8b3fb5e 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Lisää aikaa."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Vähennä aikaa."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Taskulamppu on pois päältä."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Taskulamppu ei ole käytettävissä."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Taskulamppu on päällä."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Taskulamppu poistettiin käytöstä."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Taskulamppu otettiin käyttöön."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Otetaanko Bluetooth käyttöön?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Jotta voit yhdistää näppäimistön tablettiisi, sinun on ensin otettava Bluetooth käyttöön."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ota käyttöön"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Näytä ilmoitukset hiljennettyinä"</string>
+ <string name="block" msgid="2734508760962682611">"Estä kaikki ilmoitukset"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Älä hiljennä"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Älä hiljennä tai estä"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Näytä kaikki tärkeysasetukset"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Estetyt"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Pienin tärkeys"</string>
<string name="low_importance" msgid="4109929986107147930">"Ei kovin tärkeä"</string>
<string name="default_importance" msgid="8192107689995742653">"Tärkeä"</string>
<string name="high_importance" msgid="1527066195614050263">"Hyvin tärkeä"</string>
<string name="max_importance" msgid="5089005872719563894">"Kiireellinen"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Älä koskaan näytä näitä ilmoituksia"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Hiljennä ilmoitukset ja näytä ne ilmoitusluettelon alaosassa."</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Näytä nämä ilmoitukset hiljennettyinä."</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Salli näiden ilmoitusten äänet."</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Näytä ilmoitukset näytöllä ja salli niiden äänet."</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Näytä ilmoitukset näytöllä ja ilmoitusluettelon yläosassa ja salli niiden äänet."</string>
<string name="notification_more_settings" msgid="816306283396553571">"Lisäasetukset"</string>
<string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Väri ja ulkoasu"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Näytä prosenttiluku latauksen aikana (oletus)"</item>
<item msgid="3327323682209964956">"Älä näytä tätä kuvaketta"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Muu"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Näytön jakaja"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Siirrä alaspäin"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Siirrä ylöspäin"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index b957dba..e0beeca 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Plus longtemps"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Moins longtemps."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lampe de poche désactivée."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lampe de poche indisponible."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lampe de poche activée."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lampe de poche désactivée."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lampe de poche activée."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter votre clavier à votre tablette, vous devez d\'abord activer la connectivité Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activer"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Afficher les notifications en mode silencieux"</string>
+ <string name="block" msgid="2734508760962682611">"Bloquer toutes les notifications"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Ne pas activer le mode silencieux"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Ne pas activer le mode silencieux ni bloquer"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Afficher les paramètres d\'importance complets"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Bloquée"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Importance minimale"</string>
<string name="low_importance" msgid="4109929986107147930">"Importance faible"</string>
<string name="default_importance" msgid="8192107689995742653">"Importance normale"</string>
<string name="high_importance" msgid="1527066195614050263">"Importance élevée"</string>
<string name="max_importance" msgid="5089005872719563894">"Importance urgente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Ne jamais afficher ces notifications"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Afficher en mode silencieux au bas de la liste de notifications"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Afficher ces notifications en mode silencieux"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Autoriser ces notifications à émettre des sons"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Afficher sur l\'écran et émettre un son"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Afficher en haut de la liste des notifications, afficher sur l\'écran et émettre un son"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
<string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Couleur et apparence"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Montrer le pourcentage durant la charge (par défaut)"</item>
<item msgid="3327323682209964956">"Ne pas afficher cette icône"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Autre"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Séparateur d\'écran partagé"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Déplacer vers le bas"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Déplacer vers le haut"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index a7bf20b..9ef6392 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Plus longtemps"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Moins longtemps"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lampe de poche désactivée."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lampe de poche indisponible."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lampe de poche activée."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lampe de poche désactivée."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lampe de poche activée."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer le Bluetooth ?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter un clavier à votre tablette, vous devez avoir activé le Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activer"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Afficher les notifications en mode silencieux"</string>
+ <string name="block" msgid="2734508760962682611">"Bloquer toutes les notifications"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Ne pas activer le mode silencieux"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Ne pas activer le mode silencieux ni bloquer"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Afficher les paramètres d\'importance complets"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Bloquées"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Importance minimale"</string>
<string name="low_importance" msgid="4109929986107147930">"Importance faible"</string>
<string name="default_importance" msgid="8192107689995742653">"Importance normale"</string>
<string name="high_importance" msgid="1527066195614050263">"Importance élevée"</string>
<string name="max_importance" msgid="5089005872719563894">"Urgent"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Ne jamais afficher ces notifications"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Afficher au bas de la liste des notifications en mode silencieux"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Afficher ces notifications en mode silencieux"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Autoriser ces notifications à émettre des sons"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Afficher sur l\'écran et émettre un son"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Afficher en haut de la liste des notifications, afficher sur l\'écran et émettre un son"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
<string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Couleur et apparence"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Afficher le pourcentage lorsque l\'appareil est en charge (option par défaut)"</item>
<item msgid="3327323682209964956">"Ne plus afficher cette icône"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Autre"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Séparateur d\'écran partagé"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Déplacer vers le bas"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Déplacer vers le haut"</string>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index d24c424..bb85708 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Máis tempo."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tempo."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna desactivada."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"A lanterna non está dispoñible."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna activada."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Desactivouse a lanterna."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Activouse a lanterna."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Queres activar o Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teu teclado co tablet, primeiro tes que activar o Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Mostrar notificacións de forma silenciosa"</string>
+ <string name="block" msgid="2734508760962682611">"Bloquear todas as notificacións"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Non silenciar"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Non silenciar nin bloquear"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar a configuración completa da importancia"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Bloqueada"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Importancia mínima"</string>
<string name="low_importance" msgid="4109929986107147930">"Importancia baixa"</string>
<string name="default_importance" msgid="8192107689995742653">"Importancia normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Importancia alta"</string>
<string name="max_importance" msgid="5089005872719563894">"Importancia urxente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Non mostrar nunca estas notificacións"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar de forma silenciosa na parte inferior da lista de notificacións"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar estas notificacións de forma silenciosa"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que esta notificación emita son"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Mostrar na pantalla e permitir que emita son"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar na parte superior da lista de notificacións, amosar na pantalla e permitir que emita son"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Máis opcións"</string>
<string name="notification_done" msgid="5279426047273930175">"Feito"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Cor e aspecto"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Mostrar porcentaxe durante a carga (predeterminado)"</item>
<item msgid="3327323682209964956">"Non mostrar esta icona"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Outros"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Divisor de pantalla dividida"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Baixar"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Subir"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 08dfb23..09e7f70b 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Ավելացնել ժամանակը:"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Պակասեցնել ժամանակը:"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Լապտերն անջատված է:"</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Լապտերն անհասանելի է:"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Լապտերը միացված է:"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Լապտերն անջատվեց:"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Լապտերը միացավ:"</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Միացնե՞լ Bluetooth-ը:"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Ստեղնաշարը ձեր պլանշետին միացնելու համար նախ անհրաժեշտ է միացնել Bluetooth-ը:"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Միացնել"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Ցույց տալ ծանուցումներն առանց ձայնային ազդանշանի"</string>
+ <string name="block" msgid="2734508760962682611">"Արգելափակել բոլոր ծանուցումները"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Ձայնը չանջատել"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Ձայնը չանջատել և չարգելափակել"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Ցույց տալ կարևորության բոլոր կարգավորումները"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Արգելափակված"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Նվազագույն կարևորություն"</string>
<string name="low_importance" msgid="4109929986107147930">"Ցածր կարևորություն"</string>
<string name="default_importance" msgid="8192107689995742653">"Սովորական կարևորություն"</string>
<string name="high_importance" msgid="1527066195614050263">"Բարձր կարևորություն"</string>
<string name="max_importance" msgid="5089005872719563894">"Հրատապ կարևորություն"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Երբեք չցուցադրել այս ծանուցումները"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Ցուցադրել ծանուցումների ցանկի ներքևում առանց ձայնային ազդանշանի"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Ցուցադրել այս ծանուցումներն առանց ձայնային ազդանշանի"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Թույլ տալ այս ծանուցումներին ձայնային ազդանշան հնչեցնել"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Թռուցիկ ցուցադրել էկրանին և թույլատրել ձայնային ազդանշանը"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Ցույց տալ ծանուցումների ցանկի վերևում, թռուցիկ ցուցադրել էկրանին և թույլատրել ձայնային ազդանշանը"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Այլ կարգավորումներ"</string>
<string name="notification_done" msgid="5279426047273930175">"Պատրաստ է"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Գույնը և արտաքին տեսքը"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Ցույց տալ տոկոսը լիցքավորելու ժամանակ (կանխադրված է)"</item>
<item msgid="3327323682209964956">"Ցույց չտալ այս պատկերակը"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Այլ"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Տրոհված էկրանի բաժանիչ"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Տեղափոխել ներքև"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Տեղափոխել վերև"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 3fa41be..46340a7 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Lebih lama."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Lebih cepat."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Senter nonaktif."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Senter tidak tersedia."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Senter aktif."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Senter dinonaktifkan."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Senter diaktifkan."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Aktifkan Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menghubungkan keyboard dengan tablet, terlebih dahulu aktifkan Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktifkan"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Tampilkan notifikasi tanpa suara"</string>
+ <string name="block" msgid="2734508760962682611">"Blokir semua notifikasi"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Jangan bisukan"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Jangan bisukan atau blokir"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Tampilkan setelan lengkap nilai penting"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Diblokir"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Nilai penting min"</string>
<string name="low_importance" msgid="4109929986107147930">"Tingkat kepentingan: rendah"</string>
<string name="default_importance" msgid="8192107689995742653">"Tingkat kepentingan: normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Tingkat kepentingan: tinggi"</string>
<string name="max_importance" msgid="5089005872719563894">"Tingkat kepentingan: darurat"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Jangan pernah tunjukkan notifikasi ini"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Tampilkan di bagian bawah daftar notifikasi tanpa suara"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Tampilkan notifikasi ini tanpa suara"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Izinkan notifikasi ini bersuara"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Muncul di layar dan izinkan suara"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Tampilkan di bagian atas daftar notifikasi, muncul di layar, dan izinkan suara"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Setelan lainnya"</string>
<string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Warna dan tampilan"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Tampilkan persentase saat mengisi daya (default)"</item>
<item msgid="3327323682209964956">"Jangan tampilkan ikon ini"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Lainnya"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Pembagi layar terpisah"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Turunkan"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Naikkan"</string>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index e3c3aa8..89708de 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Meiri tími."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Minni tími."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Slökkt á vasaljósi."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Vasaljós ekki tiltækt"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Kveikt á vasaljósi."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Slökkt á vasaljósi."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Kveikt á vasaljósi."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Kveikja á Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Til að geta tengt lyklaborðið við spjaldtölvuna þarftu fyrst að kveikja á Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Kveikja"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Sýna tilkynningar án hljóðs"</string>
+ <string name="block" msgid="2734508760962682611">"Loka á allar tilkynningar"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Ekki þagga"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Hvorki þagga né útiloka"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Sýna stillingar fyrir mikilvægi"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Útilokuð"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Lítill forgangur"</string>
<string name="low_importance" msgid="4109929986107147930">"Ekki svo mikilvægt"</string>
<string name="default_importance" msgid="8192107689995742653">"Venjulegt mikilvægi"</string>
<string name="high_importance" msgid="1527066195614050263">"Mjög mikilvægt"</string>
<string name="max_importance" msgid="5089005872719563894">"Afar áríðandi"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Aldrei sýna þessar tilkynningar"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Sýna neðst á tilkynningalistanum án hljóðs"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Sýna þessar tilkynningar án hljóðs"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Leyfa þessum tilkynningum að spila hljóð"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Birta á skjánum og leyfa hljóð"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Sýna efst á tilkynningalistanum, birta á skjánum og leyfa hljóð"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Fleiri stillingar"</string>
<string name="notification_done" msgid="5279426047273930175">"Lokið"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Litur og útlit"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Sýna hlutfall meðan á hleðslu stendur (sjálfgefið)"</item>
<item msgid="3327323682209964956">"Ekki sýna þetta tákn"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Annað"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Skjáskipting"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Færa niður"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Færa upp"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 5266ba8..aa6dd28 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Più tempo."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Meno tempo."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Torcia spenta."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Torcia non disponibile."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Torcia accesa."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Torcia disattivata."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Torcia attivata."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Attivare il Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connettere la tastiera al tablet, devi prima attivare il Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Attiva"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Mostra le notifiche silenziosamente"</string>
+ <string name="block" msgid="2734508760962682611">"Blocca tutte le notifiche"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Non silenziare"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Non silenziare e non bloccare"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostra impostazioni di importanza complete"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Bloccata"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Importanza minima"</string>
<string name="low_importance" msgid="4109929986107147930">"Importanza scarsa"</string>
<string name="default_importance" msgid="8192107689995742653">"Importanza normale"</string>
<string name="high_importance" msgid="1527066195614050263">"Importanza elevata"</string>
<string name="max_importance" msgid="5089005872719563894">"Importanza urgente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Non mostrare mai queste notifiche"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Mostra silenziosamente in fondo all\'elenco delle notifiche"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Mostra queste notifiche silenziosamente"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Attiva l\'audio per queste notifiche"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Visualizza sullo schermo e attiva l\'audio"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Mostra in cima all\'elenco delle notifiche, visualizza sullo schermo e attiva l\'audio"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Altre impostazioni"</string>
<string name="notification_done" msgid="5279426047273930175">"Fine"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Colore e aspetto"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Mostra la percentuale quando in carica (opzione predefinita)"</item>
<item msgid="3327323682209964956">"Non mostrare questa icona"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Altro"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Strumento per schermo diviso"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Sposta giù"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Sposta su"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index a13f975f4..ed44624 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -209,8 +209,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"יותר זמן."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"פחות זמן."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"הפנס כבוי."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"פנס אינו זמין."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"הפנס מופעל."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"הפנס נכבה."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"הפנס הופעל."</string>
@@ -458,34 +457,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"האם להפעיל את ה-Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"כדי לחבר את המקלדת לטאבלט, תחילה עליך להפעיל את ה-Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"הפעל"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"הצג הודעות בלי להשמיע צליל"</string>
+ <string name="block" msgid="2734508760962682611">"חסום את כל ההודעות"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"לא להשתיק"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"לא להשתיק או לחסום"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"הצג את הגדרות החשיבות במלואן"</string>
<string name="blocked_importance" msgid="5198578988978234161">"חסום"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"חשיבות מינימלית"</string>
<string name="low_importance" msgid="4109929986107147930">"חשיבות נמוכה"</string>
<string name="default_importance" msgid="8192107689995742653">"חשיבות רגילה"</string>
<string name="high_importance" msgid="1527066195614050263">"חשיבות גבוהה"</string>
<string name="max_importance" msgid="5089005872719563894">"חשיבות דחופה"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"לעולם אל תציג את ההודעות האלה"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"הצג בסוף רשימת ההודעות בלי להשמיע צליל"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"הצג את ההודעות האלה בלי להשמיע צליל"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"אשר להודעות אלה להשמיע צליל"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"הצג לרגע על גבי המסך ואשר השמעת צליל"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"הצג בראש רשימת ההודעות, הצג לרגע על גבי המסך ואשר השמעת צליל"</string>
<string name="notification_more_settings" msgid="816306283396553571">"הגדרות נוספות"</string>
<string name="notification_done" msgid="5279426047273930175">"סיום"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"צבע ומראה"</string>
@@ -499,7 +487,7 @@
<string name="use_dark_theme" msgid="2900938704964299312">"השתמש בעיצוב כהה למערכת ההפעלה של Android."</string>
<string name="adjust_tint" msgid="3398569573231409878">"התאמת גוון"</string>
<string name="adjust_brightness" msgid="980039329808178246">"התאמת בהירות"</string>
- <string name="night_mode_disclaimer" msgid="598914896926759578">"העיצוב הכהה מוחל על התחומים העיקריים במערכת ההפעלה של Android שמוצגים בדרך כלל בעיצוב בהיר, כמו \'הגדרות\'."</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"העיצוב הכהה מוחל על התחומים העיקריים במערכת ההפעלה Android שמוצגים בדרך כלל בעיצוב בהיר, כמו \'הגדרות\'."</string>
<string name="color_apply" msgid="9212602012641034283">"החל"</string>
<string name="color_revert_title" msgid="4746666545480534663">"אישור הגדרות"</string>
<string name="color_revert_message" msgid="9116001069397996691">"הגדרות צבע מסוימות עלולות להפוך את המכשיר הזה לבלתי שמיש. לחץ על אישור כדי לאשר את הגדרות הצבע האלה, אחרת הגדרות אלה יתאפסו לאחר 10 שניות."</string>
@@ -558,8 +546,7 @@
<item msgid="2139628951880142927">"הצג באחוזים בזמן טעינה (ברירת מחדל)"</item>
<item msgid="3327323682209964956">"אל תציג את הסמל הזה"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"אחר"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"מחלק מסך מפוצל"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"הזז למטה"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"הזז למעלה"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index d3a8b2c..f104703 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"長くします。"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"短くします。"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ライトがOFFです。"</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ライトを使用できません。"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ライトがONです。"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ライトをOFFにしました。"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ライトをONにしました。"</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"BluetoothをONにしますか?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"タブレットでキーボードに接続するには、最初にBluetoothをONにする必要があります。"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ONにする"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"通知をマナーモードで表示する"</string>
+ <string name="block" msgid="2734508760962682611">"通知をすべてブロックする"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"音声で知らせる"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"音声で知らせる / ブロックしない"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"重要度の設定をすべて表示"</string>
<string name="blocked_importance" msgid="5198578988978234161">"ブロック中"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"重要度: 最低"</string>
<string name="low_importance" msgid="4109929986107147930">"重要度: 低"</string>
<string name="default_importance" msgid="8192107689995742653">"重要度: 中"</string>
<string name="high_importance" msgid="1527066195614050263">"重要度: 高"</string>
<string name="max_importance" msgid="5089005872719563894">"重要度: 緊急"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"今後はこの通知を表示しない"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"通知リストの末尾にマナーモードで表示する"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"この通知をマナーモードで表示する"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"通知を音声で知らせる"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"画面に数秒間表示し、音声でも知らせる"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"通知リストの先頭に表示し、画面に数秒間表示し、音声でも知らせる"</string>
<string name="notification_more_settings" msgid="816306283396553571">"詳細設定"</string>
<string name="notification_done" msgid="5279426047273930175">"完了"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"色と表示"</string>
@@ -559,8 +547,7 @@
<item msgid="2139628951880142927">"変更時に割合を表示(デフォルト)"</item>
<item msgid="3327323682209964956">"このアイコンを表示しない"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"その他"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"分割画面の分割線"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"下に移動"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"上に移動"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index d14a3c9..b365eb3 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"მეტი დრო."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"ნაკლები დრო."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ფანარი გამორთულია."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ფანარი მიუწვდომელია."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ფანარი ჩართულია."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ფანარი გამოირთო."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ფანარი ჩაირთო."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"გსურთ Bluetooth-ის ჩართვა?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"კლავიატურის ტაბლეტთან დასაკავშირებლად, ჯერ უნდა ჩართოთ Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ჩართვა"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"შეტყობინებების უხმოდ ჩვენება"</string>
+ <string name="block" msgid="2734508760962682611">"ყველა შეტყობინების დაბლოკვა"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"არ გაჩუმდეს"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"არ გაჩუმდეს ან დაიბლოკოს"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"მნიშვნელობის დონის სრული პარამეტრების ჩვენება"</string>
<string name="blocked_importance" msgid="5198578988978234161">"დაბლოკილი"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"მინიმალური"</string>
<string name="low_importance" msgid="4109929986107147930">"დაბალი პრიორიტეტი"</string>
<string name="default_importance" msgid="8192107689995742653">"ჩვეულებრივი პრიორიტეტი"</string>
<string name="high_importance" msgid="1527066195614050263">"მაღალი პრიორიტეტი"</string>
<string name="max_importance" msgid="5089005872719563894">"გადაუდებელი"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"ამ შეტყობინებების ჩვენების შეწყვეტა"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"შეტყობინებების სიის ბოლოში, უხმოდ ჩვენება"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"ამ შეტყობინებების უხმოდ ჩვენება"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"ამ შეტყობინებებისთვის ხმის გამოცემის დაშვება"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"შეტყობინებების პირდაპირ ეკრანზე ჩვენება და ხმის დაშვება"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"შეტყობინებების სიის თავში ჩვენება, პირდაპირ ეკრანზე გამოჩენა და ხმის დაშვება"</string>
<string name="notification_more_settings" msgid="816306283396553571">"დამატებითი პარამეტრები"</string>
<string name="notification_done" msgid="5279426047273930175">"მზადაა"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"ფერი და იერსახე"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"პროცენტულობის დატენვისას ჩვენება (ნაგულისხმევი)"</item>
<item msgid="3327323682209964956">"აღარ მაჩვენო ეს ხატულა"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"სხვა"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"გაყოფილი ეკრანის რეჟიმის გამყოფი"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"ქვემოთ გადატანა"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ზემოთ გადატანა"</string>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index a2346b3..720caec 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Көбірек уақыт."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Азырақ уақыт."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Қол шам өшірулі."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Жарқыл қол жетімді емес."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Қол шам қосулы."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Қол шам өшірілді."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Қол шам қосылды."</string>
@@ -304,8 +303,7 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"экранды бекіту"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"іздеу"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> іске қосу мүмкін болмады."</string>
- <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
- <skip />
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> қауіпсіз режимде өшіріледі."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Тарих"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Тазалау"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Бұл қолданба көп терезені қолдамайды"</string>
@@ -457,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth функциясын қосу керек пе?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Пернетақтаны планшетке қосу үшін алдымен Bluetooth функциясын қосу керек."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Қосу"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Хабарландыруларды үнсіз көрсету"</string>
+ <string name="block" msgid="2734508760962682611">"Барлық хабарландыруларды бұғаттау"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Үнін өшірмеу"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Үнін өшірмеу немесе бұғаттамау"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Толық маңыздылық параметрлерін көрсету"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Бөгелген"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Ең аз маңыздылық"</string>
<string name="low_importance" msgid="4109929986107147930">"Төмен маңыздылық"</string>
<string name="default_importance" msgid="8192107689995742653">"Қалыпты маңыздылық"</string>
<string name="high_importance" msgid="1527066195614050263">"Жоғары маңыздылық"</string>
<string name="max_importance" msgid="5089005872719563894">"Шұғыл маңыздылық"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Осы хабарландыруларды ешқашан көрсетпеу"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Хабарландырулар тізімнің төменгі жағында үнсіз көрсету"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Осы хабарландыруларды үнсіз көрсету"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Осы хабарландыруға дыбыстар шығаруға рұқсат ету"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Экранда көрсету және дыбыс шығаруға рұқсат ету"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Хабарландырулар тізімінің жоғарғы жағында көрсету, экранда көрсету және дыбысқа рұқсат ету"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Қосымша параметрлер"</string>
<string name="notification_done" msgid="5279426047273930175">"Дайын"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Түс және сыртқы түрі"</string>
@@ -498,7 +485,7 @@
<string name="use_dark_theme" msgid="2900938704964299312">"Android ОЖ үшін күңгірт тақырыпты пайдалану"</string>
<string name="adjust_tint" msgid="3398569573231409878">"Реңкті реттеу"</string>
<string name="adjust_brightness" msgid="980039329808178246">"Жарықтықты реттеу"</string>
- <string name="night_mode_disclaimer" msgid="598914896926759578">"Күңгірт тақырып Android операциялық жүйесінің әдетте ашық тақырыпта көрсетілетін негізгі аумақтарына қолданылады, мысалы, \"Параметрлер\" тармағына."</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Күңгірт тақырып Android операциялық жүйесінің әдетте \"Параметрлер\" сияқты ашық тақырыпта көрсетілетін негізгі аумақтарына қолданылады."</string>
<string name="color_apply" msgid="9212602012641034283">"Қолдану"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Параметрлерді растау"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Кейбір түс параметрлері бұл құрылғыны пайдалану мүмкін емес етуі мүмкін. Бұл түс параметрлерін растау үшін OK түймесін басыңыз, әйтпесе параметрлер 10 секундтан кейін ысырылады."</string>
@@ -557,8 +544,7 @@
<item msgid="2139628951880142927">"Зарядтау кезінде пайызды көрсету (әдепкі)"</item>
<item msgid="3327323682209964956">"Бұл белгішені көрсетпеу"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Басқа"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Бөлінген экран бөлгіші"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Төмен қарай жылжыту"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Жоғары қарай жылжыту"</string>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index d5ac252..96ffa96 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -73,7 +73,7 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Скриншот тартылды."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Тийип, скриншотту көрүңүз."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Скриншот кылынбай жатат."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Эстутумда бош орун чектелүү болгондуктан скриншот сакталбай жатат."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Сактагычта бош орун аз болгондуктан скриншот сакталбай жатат."</string>
<string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Скриншот тартууга колдонмо же ишканаңыз уруксат бербейт."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB менен файл өткөрүү мүмкүнчүлүктөрү"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Медиа ойноткуч катары кошуу (MTP)"</string>
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Көбүрөөк убакыт."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Азыраак убакыт."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Колчырак өчүк."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Кол чырак жок."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Колчырак күйүк."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Колчырак өчүрүлдү."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Колчырак күйгүзүлдү."</string>
@@ -307,8 +306,8 @@
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> коопсуз режиминде өчүрүлдү."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Таржымал"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Тазалоо"</string>
- <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Бул колдонмо мульти-терезени колдоого албайт"</string>
- <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Колдонмо мульти-терезени колдоого албайт"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Бул колдонмодо бир нече терезе режими колдоого алынбайт"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Колдонмодо бир нече терезе режими колдоого алынбайт"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Туурасынан бөлүү"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Тигинен бөлүү"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Ыңгайлаштырылган бөлүү"</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth күйгүзүлсүнбү?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Баскычтобуңузду планшетиңизге туташтыруу үчүн, адегенде Bluetooth\'ту күйгүзүшүңүз керек."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Күйгүзүү"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Эскертмелер үнсүз көрсөтүлсүн"</string>
+ <string name="block" msgid="2734508760962682611">"Бардык эскертмелерди бөгөттөө"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Үнү менен көрсөтүлсүн"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Үнү менен көрсөтүлүп бөгөттөлбөсүн"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Маанилүүлүк жөндөөлөрү толук көрсөтүлсүн"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Бөгөттөлгөн"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Маанилүүлүгү эң төмөн"</string>
<string name="low_importance" msgid="4109929986107147930">"Маанилүүлүгү төмөн"</string>
<string name="default_importance" msgid="8192107689995742653">"Маанилүүлүгү орточо"</string>
<string name="high_importance" msgid="1527066195614050263">"Маанилүүлүгү жогору"</string>
<string name="max_importance" msgid="5089005872719563894">"Маанилүүлүгү шашылыш"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Бул эскертмелер эч качан көрсөтүлбөсүн"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Эскертмелер тизмесинин соңунда үнсүз көрсөтүлсүн"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Бул эскертмелер үнсүз көрсөтүлсүн"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Бул эскертмелер үнү менен көрсөтүлсүн"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Үн менен коштолуп, экранга чыгарылсын"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Эскертмелер тизмесинин эң башында көрсөтүлүп, үн менен коштолуп, экранга чыгарылсын"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Дагы жөндөөлөр"</string>
<string name="notification_done" msgid="5279426047273930175">"Аткарылды"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Түсү жана көрүнүшү"</string>
@@ -497,7 +485,7 @@
<string name="use_dark_theme" msgid="2900938704964299312">"Android OS үчүн караңгы тема колдонуу"</string>
<string name="adjust_tint" msgid="3398569573231409878">"Кошумча түсүн тууралоо"</string>
<string name="adjust_brightness" msgid="980039329808178246">"Жарыктыгын тууралоо"</string>
- <string name="night_mode_disclaimer" msgid="598914896926759578">"Адатта жарык темада көрсөтүлгөн Android OS\'тин, Жөндөөлөр сыяктуу негизги аймактарына караңгы тема колдонулат."</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Адатта жарык темада көрсөтүлүүчү Android тутумунун негизги элементтерине (Жөндөөлөр сыяктуу) колдонула турган караңгы тема."</string>
<string name="color_apply" msgid="9212602012641034283">"Колдонуу"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Жөндөөлөрдү ырастоо"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Айрым түс жөндөөлөрү бул түзмөктү колдонулгус кылып коюшу мүмкүн. Бул түс жөндөөлөрүн ырастоо үчүн OK баскычын чыкылдатыңыз, болбосо бул жөндөөлөр 10 секунддан кийин баштапкы абалына келтирилет."</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Кубаттоо учурунда пайызы көрсөтүлсүн (демейки)"</item>
<item msgid="3327323682209964956">"Бул сөлөкөт көрсөтүлбөсүн"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Башка"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Экранды бөлгүч"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Төмөн жылдыруу"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Жогору жылдыруу"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index a33c76f..bb49c39 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -209,8 +209,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Daugiau laiko."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mažiau laiko."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Blykstė išjungta."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Blykstė nepasiekiama."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Blykstė įjungta."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Blykstė išjungta."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Blykstė įjungta."</string>
@@ -458,34 +457,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Įjungti „Bluetooth“?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Kad galėtumėte prijungti klaviatūrą prie planšetinio kompiuterio, pirmiausia turite įjungti „Bluetooth“."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Įjungti"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Tyliai rodyti pranešimus"</string>
+ <string name="block" msgid="2734508760962682611">"Blokuoti visus pranešimus"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Netylėti"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Netylėti arba blokuoti"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Rodyti visos svarbos nustatymus"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Užblokuota"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Min. svarba"</string>
<string name="low_importance" msgid="4109929986107147930">"Maža svarba"</string>
<string name="default_importance" msgid="8192107689995742653">"Įprasta svarba"</string>
<string name="high_importance" msgid="1527066195614050263">"Didelė svarba"</string>
<string name="max_importance" msgid="5089005872719563894">"Skubi svarba"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Niekada nerodyti šių pranešimų"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Tyliai rodyti pranešimų sąrašo apačioje"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Tyliai rodyti šiuos pranešimus"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Leisti šiems pranešimams skambėti"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Rodyti ekrane ir leisti skambėti"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Rodyti pranešimų sąrašo viršuje, rodyti ekrane ir leisti skambėti"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Daugiau nustatymų"</string>
<string name="notification_done" msgid="5279426047273930175">"Atlikta"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Spalva ir išvaizda"</string>
@@ -558,8 +546,7 @@
<item msgid="2139628951880142927">"Rodyti procentus kraunant (numatytasis nustatymas)"</item>
<item msgid="3327323682209964956">"Nerodyti šios piktogramos"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Kita"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Skaidyto ekrano daliklis"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Perkelti žemyn"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Perkelti aukštyn"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 683e00a..574889e 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -208,8 +208,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Vairāk laika."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mazāk laika."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Apgaismojums ir izslēgts."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Zibspuldze nav pieejama."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Apgaismojums ir ieslēgts."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Apgaismojums ir izslēgts."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Apgaismojums ir ieslēgts."</string>
@@ -457,34 +456,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vai ieslēgt Bluetooth savienojumu?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Lai pievienotu tastatūru planšetdatoram, vispirms ir jāieslēdz Bluetooth savienojums."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ieslēgt"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Rādīt paziņojumus bez skaņas signāla"</string>
+ <string name="block" msgid="2734508760962682611">"Bloķēt visus paziņojumus"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Neizslēgt skaņu"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Neizslēgt skaņu vai nebloķēt"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Rādīt ļoti svarīgu paziņojumu iestatījumus"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Bloķēts"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Minimāls svarīguma līmenis"</string>
<string name="low_importance" msgid="4109929986107147930">"Nav svarīgs"</string>
<string name="default_importance" msgid="8192107689995742653">"Parasts"</string>
<string name="high_importance" msgid="1527066195614050263">"Ļoti svarīgs"</string>
<string name="max_importance" msgid="5089005872719563894">"Steidzams"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Nekad nerādīt šos paziņojumus"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Rādīt paziņojumu saraksta apakšdaļā bez skaņas signāla"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Rādīt šos paziņojumus bez skaņas signāla"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Atļaut skaņas signālu šiem paziņojumiem"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Rādīt ekrānā un atļaut skaņas signālu"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Rādīt paziņojumu saraksta augšdaļā, rādīt ekrānā ar skaņas signālu"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Citi iestatījumi"</string>
<string name="notification_done" msgid="5279426047273930175">"Gatavs"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Krāsas un izskats"</string>
@@ -557,8 +545,7 @@
<item msgid="2139628951880142927">"Rādīt procentuālo vērtību uzlādes laikā (noklusējums)"</item>
<item msgid="3327323682209964956">"Nerādīt šo ikonu"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Citi"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Ekrāna sadalītājs"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pārvietot uz leju"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pārvietot uz augšu"</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index fea38a9..a69be1f 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -205,8 +205,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Хугацаа нэмэх."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Хугацаа хасах."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Флаш гэрэл унтарсан."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Гэрэлтүүлэгч боломжгүй байна."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Флаш гэрэл ассан."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Флаш гэрлийг унтраасан."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Флаш гэрлийг асаасан."</string>
@@ -454,34 +453,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth-г асаах уу?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Компьютерийн гараа таблетад холбохын тулд эхлээд Bluetooth-г асаана уу."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Асаах"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Мэдэгдлийг чимээгүй харуулах"</string>
+ <string name="block" msgid="2734508760962682611">"Бүх мэдэгдлийг блоклох"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Дуугүй болгох хэрэггүй"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Дууг нь хаах эсвэл блоклох хэрэггүй"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Бүрэн ач холбогдлын тохиргоог харуулах"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Блоклосон"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Хамгийн бага ач холбогдол"</string>
<string name="low_importance" msgid="4109929986107147930">"Бага ач холбогдолтой"</string>
<string name="default_importance" msgid="8192107689995742653">"Энгийн ач холбогдолтой"</string>
<string name="high_importance" msgid="1527066195614050263">"Өндөр ач холбогдолтой"</string>
<string name="max_importance" msgid="5089005872719563894">"Яаралтай ач холбогдолтой"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Эдгээр мэдэгдлийг хэзээ ч харуулахгүй"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Мэдэгдлийг жагсаалтын доод хэсэгт дуугүй харуулах"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Эдгээр мэдэгдлийг дуугүй харуулах"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Эдгээр мэдэгдлийг дуу гаргахыг зөвшөөрөх"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Дэлгэцэд яаралтайгаар дуутай гаргах"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Мэдэгдлийг жагсаалтын эхэнд яаралтай дуутай харуулах"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Бусад тохиргоо"</string>
<string name="notification_done" msgid="5279426047273930175">"Дууссан"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Өнгө, харагдах байдал"</string>
@@ -554,8 +542,7 @@
<item msgid="2139628951880142927">"Цэнэглэх үед хувийг тогтмол харуулах (өгөгдмөл)"</item>
<item msgid="3327323682209964956">"Энэ дүрс тэмдгийг бүү үзүүл"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Бусад"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"\"Дэлгэц хуваах\" хуваагч"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Доош зөөх"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Дээш зөөх"</string>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index acd9d4e..d99678c 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"अधिक वेळ."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"कमी वेळ."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"फ्लॅशलाइट बंद."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"फ्लॅशलाइट अनुपलब्ध आहे."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"फ्लॅशलाइट चालू."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"फ्लॅशलाइट बंद केला."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"फ्लॅशलाइट चालू केला."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटुथ सुरू करायचे?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"आपला कीबोर्ड आपल्या टॅब्लेटसह कनेक्ट करण्यासाठी, आपल्याला प्रथम ब्लूटुथ चालू करणे आवश्यक आहे."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"चालू करा"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"सूचना शांतपणे दर्शवा"</string>
+ <string name="block" msgid="2734508760962682611">"सर्व सूचना अवरोधित करा"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"शांत करू नका"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"शांत किंवा अवरोधित करू नका"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"पूर्ण महत्त्व सेटिंग्ज दर्शवा"</string>
<string name="blocked_importance" msgid="5198578988978234161">"अवरोधित केले"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"किमान महत्त्व"</string>
<string name="low_importance" msgid="4109929986107147930">"कमी महत्त्व"</string>
<string name="default_importance" msgid="8192107689995742653">"सामान्य महत्त्व"</string>
<string name="high_importance" msgid="1527066195614050263">"सर्वाधिक महत्व"</string>
<string name="max_importance" msgid="5089005872719563894">"त्वरित महत्त्व"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"या सूचना कधीही दर्शवू नका"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"सूचना सूचीच्या तळाशी शांतपणे दर्शवा"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"या सूचना शांतपणे दर्शवा"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"या सूचनांना ध्वनी चालू करण्याची अनुमती द्या"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"स्क्रीनवर पहा आणि ध्वनीस अनुमती द्या ध्वनीस अनुमती द्या"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"सूचनांच्या शीर्षस्थानी दर्शवा, स्क्रीनवर पहा आणि ध्वनीस अनुमती द्या"</string>
<string name="notification_more_settings" msgid="816306283396553571">"अधिक सेटिंग्ज"</string>
<string name="notification_done" msgid="5279426047273930175">"पूर्ण झाले"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"रंग आणि स्वरूप"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"चार्ज करताना टक्केवारी दर्शवा (डीफॉल्ट)"</item>
<item msgid="3327323682209964956">"हे चिन्ह दर्शवू नका"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"अन्य"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"विभाजित-स्क्रीन विभाजक"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"खाली हलवा"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"वर हलवा"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index d204830..a716eef 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Lagi masa."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kurang masa."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lampu suluh dimatikan."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lampu suluh tidak tersedia."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lampu suluh dihidupkan."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lampu suluh dimatikan."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lampu suluh dihidupkan."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Hidupkan Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menyambungkan papan kekunci anda dengan tablet, anda perlu menghidupkan Bluetooth terlebih dahulu."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Hidupkan"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Tunjukkan pemberitahuan secara senyap"</string>
+ <string name="block" msgid="2734508760962682611">"Sekat semua pemberitahuan"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Jangan senyapkan"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Jangan senyapkan atau sekat"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Tunjukkan tetapan kepentingan penuh"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Disekat"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Kurang penting"</string>
<string name="low_importance" msgid="4109929986107147930">"Kepentingan rendah"</string>
<string name="default_importance" msgid="8192107689995742653">"Kepentingan biasa"</string>
<string name="high_importance" msgid="1527066195614050263">"Kepentingan tinggi"</string>
<string name="max_importance" msgid="5089005872719563894">"Kepentingan segera"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Jangan sekali-kali tunjukkan pemberitahuan ini"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Tunjukkan pada bahagian bawah senarai pemberitahuan secara senyap"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Tunjukkan pemberitahuan ini secara senyap"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Benarkan pemberitahuan ini berbunyi"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Intai pada skrin dan benarkan bunyi"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Tunjukkan pada bahagian atas senarai pemberitahuan, intai pada skrin dan benarkan bunyi"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Lagi tetapan"</string>
<string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Warna dan penampilan"</string>
@@ -556,9 +544,8 @@
<item msgid="2139628951880142927">"Tunjukkan peratusan semasa mengecas (lalai)"</item>
<item msgid="3327323682209964956">"Jangan tunjukkan ikon ini"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
- <string name="accessibility_divider" msgid="5903423481953635044">"Pembahagi skrin terpisah"</string>
+ <string name="other" msgid="4060683095962566764">"Lain-lain"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"Pembahagi skrin pisah"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Alih ke bawah"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Alih ke atas"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Alih ke kiri"</string>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index c88eda2..503b91f 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -306,8 +306,8 @@
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ကို ဘေးကင်းလုံခြုံသည့်မုဒ်တွင် ပိတ်ထားပါသည်။"</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"မှတ်တမ်း"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ရှင်းလင်းပါ"</string>
- <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ဤအက်ပ်သည် ဝင်းဒိုးများစွာတွင်ဖွင့်ရန် မပံ့ပိုးထားပါ"</string>
- <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"အက်ပ်သည် ဝင်းဒိုးများစွာတွင်ဖွင့်ရန် မပံ့ပိုးထားပါ"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ဤအက်ပ်သည် ဝင်းဒိုးများစွာဖွင့်ခြင်းကို ပံ့ပိုးမထားပါ"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"အက်ပ်သည် ဝင်းဒိုးများစွာဖွင့်ခြင်းကို ပံ့ပိုးမထားပါ"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ရေပြင်ညီ ပိုင်းမည်"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ဒေါင်လိုက်ပိုင်းမည်"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"စိတ်ကြိုက် ပိုင်းမည်"</string>
@@ -545,7 +545,7 @@
<item msgid="3327323682209964956">"ဤသင်္ကေတပုံကို မပြပါနှင့်"</item>
</string-array>
<string name="other" msgid="4060683095962566764">"အခြား"</string>
- <string name="accessibility_divider" msgid="5903423481953635044">"မျက်နှာပြင်ခွဲခြမ်းခြင်း ပိုင်းခြားပေးသည့်စနစ်"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"မျက်နှာပြင်ခွဲခြမ်း ပိုင်းခြားပေးသည့်စနစ်"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"အောက်သို့ရွှေ့ပါ"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"အပေါ်သို့ရွှေ့ပါ"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ဘယ်ဘက်သို့ရွှေ့ပါ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index ac8cc8d..b3de239 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mer tid."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mindre tid."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lommelykten er av."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lommelykt er ikke tilgjengelig."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lommelykten er på."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lommelykten er slått av."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lommelykten er slått på."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå på Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"For å koble tastaturet til nettbrettet ditt må du først slå på Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Slå på"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Vis varsler uten lyd"</string>
+ <string name="block" msgid="2734508760962682611">"Blokkér alle varsler"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Ikke slå av lyden"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Ikke slå av lyden eller blokkér anrop"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Vis alle viktighetsinnstillingene"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Blokkert"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Laveste prioritet"</string>
<string name="low_importance" msgid="4109929986107147930">"Lav viktighet"</string>
<string name="default_importance" msgid="8192107689995742653">"Vanlig viktighet"</string>
<string name="high_importance" msgid="1527066195614050263">"Høy viktighet"</string>
<string name="max_importance" msgid="5089005872719563894">"Svært høy viktighet"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Aldri vis disse varslene"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Vis nederst på varsellisten uten lyd"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Vis disse varslene uten lyd"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Tillat at disse varslene vises med lyd"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Vis fort på skjermen og tillat lyd"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Vis øverst på varsellisten, vis fort på skjermen og tillat lyd"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Flere innstillinger"</string>
<string name="notification_done" msgid="5279426047273930175">"Ferdig"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Farge og utseende"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Vis prosentandel under lading (standard)"</item>
<item msgid="3327323682209964956">"Ikke vis dette ikonet"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Annet"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Skilleelement for delt skjerm"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Flytt ned"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Flytt opp"</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 4b78552..2008553 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -303,8 +303,7 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"स्क्रिन पिन गर्दै"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"खोजी गर्नुहोस्"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"सुरु गर्न सकिएन <xliff:g id="APP">%s</xliff:g>।"</string>
- <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
- <skip />
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> लाई सुरक्षित-मोडमा असक्षम गरिएको छ।"</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"इतिहास"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"मेटाउनुहोस्"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"यस अनुप्रयोगले बहु-विन्डोलाई समर्थन गर्दैन"</string>
@@ -456,11 +455,11 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लुटुथ सक्रिय पार्ने हो?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"आफ्नो ट्याब्लेटसँग किबोर्ड जोड्न, पहिले तपाईँले ब्लुटुथ सक्रिय गर्नुपर्छ।"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"सक्रिय पार्नुहोस्"</string>
- <string name="show_silently" msgid="6841966539811264192">"सूचनाहरूलाई बिना आवाज देखाउनुहोस्"</string>
+ <string name="show_silently" msgid="6841966539811264192">"सूचनाहरूलाई बिना आवाज देखाउने"</string>
<string name="block" msgid="2734508760962682611">"सबै सूचनाहरूलाई रोक्नुहोस्"</string>
<string name="do_not_silence" msgid="6878060322594892441">"मौन नगर्नुहोस्"</string>
<string name="do_not_silence_block" msgid="4070647971382232311">"मौन नगर्नुहोस् वा नरोक्नुहोस्"</string>
- <string name="tuner_full_importance_settings" msgid="8103289238676424226">"पूर्ण महत्त्व सेटिङहरू देखाउनुहोस्"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"पूर्ण महत्त्व सेटिङहरू देखाउने"</string>
<string name="blocked_importance" msgid="5198578988978234161">"रोकियो"</string>
<string name="min_importance" msgid="1901894910809414782">"न्यूनतम महत्त्व"</string>
<string name="low_importance" msgid="4109929986107147930">"न्यून महत्त्व"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index c9821ee..974685c 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -209,8 +209,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Więcej czasu."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mniej czasu."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Latarka wyłączona."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Latarka niedostępna."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Latarka włączona."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Latarka została wyłączona."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Latarka została włączona."</string>
@@ -458,34 +457,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Włączyć Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Aby połączyć klawiaturę z tabletem, musisz najpierw włączyć Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Włącz"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Pokazuj powiadomienia bez sygnału dźwiękowego"</string>
+ <string name="block" msgid="2734508760962682611">"Blokuj wszystkie powiadomienia"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Nie ignoruj"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Nie ignoruj ani nie blokuj"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Pokaż pełne ustawienia ważności"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Zablokowane"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Najmniejsza ważność"</string>
<string name="low_importance" msgid="4109929986107147930">"Mało ważne"</string>
<string name="default_importance" msgid="8192107689995742653">"Ważne"</string>
<string name="high_importance" msgid="1527066195614050263">"Bardzo ważne"</string>
<string name="max_importance" msgid="5089005872719563894">"Pilne"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Nigdy nie pokazuj tych powiadomień"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Pokazuj na końcu listy powiadomień bez sygnału dźwiękowego"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Pokazuj te powiadomienia bez sygnału dźwiękowego"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Zezwól na sygnalizowanie tych powiadomień dźwiękiem"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Wyświetlaj na ekranie i sygnalizuj dźwiękiem"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Pokazuj na początku listy powiadomień, wyświetlaj na ekranie i sygnalizuj dźwiękiem"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Więcej ustawień"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotowe"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Kolor i wygląd"</string>
@@ -558,8 +546,7 @@
<item msgid="2139628951880142927">"Pokazuj procent podczas ładowania (domyślnie)"</item>
<item msgid="3327323682209964956">"Nie pokazuj tej ikony"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Inne"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Linia dzielenia ekranu"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Przesuń w dół"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Przesuń w górę"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index a15a789..3797adc 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mais tempo."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tempo."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna desativada."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lanterna indisponível."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna ativada."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"A lanterna foi desativada."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"A lanterna foi ativada."</string>
@@ -457,34 +456,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Mostrar notificações de forma silenciosa"</string>
+ <string name="block" msgid="2734508760962682611">"Bloquear todas as notificações"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Não silenciar"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Não silenciar ou bloquear"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar todas as configurações de importância"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Bloqueadas"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Importância mínima"</string>
<string name="low_importance" msgid="4109929986107147930">"Importância baixa"</string>
<string name="default_importance" msgid="8192107689995742653">"Importância normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Importância elevada"</string>
<string name="max_importance" msgid="5089005872719563894">"Importância urgente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Nunca mostrar essas notificações"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar essas notificações de forma silenciosa"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que essas notificações emitam sons"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Mostrar parcialmente na tela e permitir som"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar na parte superior da lista de notificações, mostrar parcialmente na tela e permitir sons"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
<string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Cor e aparência"</string>
@@ -498,7 +486,7 @@
<string name="use_dark_theme" msgid="2900938704964299312">"Usar o tema escuro para o SO Android"</string>
<string name="adjust_tint" msgid="3398569573231409878">"Ajustar tonalidade"</string>
<string name="adjust_brightness" msgid="980039329808178246">"Ajustar brilho"</string>
- <string name="night_mode_disclaimer" msgid="598914896926759578">"O tema escuro é aplicado a áreas centrais do sistema operacional Android que normalmente são exibidas em um tema claro, como asconfigurações."</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"O tema escuro é aplicado a áreas centrais do sistema operacional Android que normalmente são exibidas em um tema claro, como as configurações."</string>
<string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Confirmar configurações"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Algumas configurações de cor podem tornar o dispositivo inutilizável. Clique em \"OK\" para confirmar essas configurações de cor; caso contrário, essas configurações serão redefinidas após 10 segundos."</string>
@@ -557,8 +545,7 @@
<item msgid="2139628951880142927">"Mostrar porcentagem durante o carregamento (padrão)"</item>
<item msgid="3327323682209964956">"Não mostrar este ícone"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Outros"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Divisor de tela"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mover para baixo"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 85d4c79..7ee2554 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mais tempo."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tempo."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna desligada."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lanterna indisponível."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna ligada."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lanterna desligada."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lanterna ligada."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Pretende ativar o Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para ligar o teclado ao tablet, tem de ativar primeiro o Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Mostrar notificações sem som"</string>
+ <string name="block" msgid="2734508760962682611">"Bloquear todas as notificações"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Não silenciar"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Não silenciar nem bloquear"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar definições de importância completas"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Bloqueado"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Importância mín."</string>
<string name="low_importance" msgid="4109929986107147930">"Importância baixa"</string>
<string name="default_importance" msgid="8192107689995742653">"Importância normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Importância alta"</string>
<string name="max_importance" msgid="5089005872719563894">"Urgente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Nunca mostrar estas notificações"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar na parte inferior da lista de notificações sem som"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar estas notificações sem som"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que estas notificações emitam sons"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Mostrar no ecrã e permitir som"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar na parte superior da lista de notificações, mostrar no ecrã e permitir som"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Mais definições"</string>
<string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Cor e aspeto"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Mostrar a percentagem durante o carregamento (predefinição)"</item>
<item msgid="3327323682209964956">"Não mostrar este ícone"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Outro"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Divisor do ecrã dividido"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mover para baixo"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index a15a789..3797adc 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mais tempo."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tempo."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna desativada."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lanterna indisponível."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna ativada."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"A lanterna foi desativada."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"A lanterna foi ativada."</string>
@@ -457,34 +456,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Mostrar notificações de forma silenciosa"</string>
+ <string name="block" msgid="2734508760962682611">"Bloquear todas as notificações"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Não silenciar"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Não silenciar ou bloquear"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar todas as configurações de importância"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Bloqueadas"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Importância mínima"</string>
<string name="low_importance" msgid="4109929986107147930">"Importância baixa"</string>
<string name="default_importance" msgid="8192107689995742653">"Importância normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Importância elevada"</string>
<string name="max_importance" msgid="5089005872719563894">"Importância urgente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Nunca mostrar essas notificações"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar essas notificações de forma silenciosa"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que essas notificações emitam sons"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Mostrar parcialmente na tela e permitir som"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar na parte superior da lista de notificações, mostrar parcialmente na tela e permitir sons"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
<string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Cor e aparência"</string>
@@ -498,7 +486,7 @@
<string name="use_dark_theme" msgid="2900938704964299312">"Usar o tema escuro para o SO Android"</string>
<string name="adjust_tint" msgid="3398569573231409878">"Ajustar tonalidade"</string>
<string name="adjust_brightness" msgid="980039329808178246">"Ajustar brilho"</string>
- <string name="night_mode_disclaimer" msgid="598914896926759578">"O tema escuro é aplicado a áreas centrais do sistema operacional Android que normalmente são exibidas em um tema claro, como asconfigurações."</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"O tema escuro é aplicado a áreas centrais do sistema operacional Android que normalmente são exibidas em um tema claro, como as configurações."</string>
<string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Confirmar configurações"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Algumas configurações de cor podem tornar o dispositivo inutilizável. Clique em \"OK\" para confirmar essas configurações de cor; caso contrário, essas configurações serão redefinidas após 10 segundos."</string>
@@ -557,8 +545,7 @@
<item msgid="2139628951880142927">"Mostrar porcentagem durante o carregamento (padrão)"</item>
<item msgid="3327323682209964956">"Não mostrar este ícone"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Outros"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Divisor de tela"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mover para baixo"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index fc1ed2f..c2bec08 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -208,8 +208,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mai mult timp."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mai puțin timp."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna este dezactivată."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lanterna nu este disponibilă."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna este activată."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lanterna este dezactivată."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lanterna este activată."</string>
@@ -457,34 +456,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Activați Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Pentru a conecta tastatura la tabletă, mai întâi trebuie să activați Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activați"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Notificările se afișează fără a se emite un sunet"</string>
+ <string name="block" msgid="2734508760962682611">"Blocați toate notificările"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Nu dezactivați sunetul"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Nu dezactivați sunetul și nu blocați"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Afișați toate setările privind importanța"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Blocate"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Importanță minimă"</string>
<string name="low_importance" msgid="4109929986107147930">"Importanță redusă"</string>
<string name="default_importance" msgid="8192107689995742653">"Importanță normală"</string>
<string name="high_importance" msgid="1527066195614050263">"Importanță ridicată"</string>
<string name="max_importance" msgid="5089005872719563894">"Importanță: urgente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Aceste notificări nu se afișează niciodată"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Se afișează în partea de jos a listei cu notificări fără a se emite un sunet"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Aceste notificări se afișează fără a se emite un sunet"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Permiteți acestor notificări să emită sunete"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Se afișează pentru o scurtă durată pe ecran și se permite un sunet"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Apar în partea de sus a listei cu notificări, se afișează pentru scurt timp pe ecran și se permite un sunet"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Mai multe setări"</string>
<string name="notification_done" msgid="5279426047273930175">"Terminat"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Culoare și aspect"</string>
@@ -557,8 +545,7 @@
<item msgid="2139628951880142927">"Afișează procentajul când se încarcă (prestabilit)"</item>
<item msgid="3327323682209964956">"Nu afișa această pictogramă"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Altele"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Separator pentru ecranul împărțit"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mutați în jos"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mutați în sus"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 5340d95..8ece7fa 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -209,8 +209,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Увеличить время."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Уменьшить время."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Фонарик отключен."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Фонарик недоступен."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Фонарик включен."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Фонарик отключен."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Фонарик включен."</string>
@@ -458,34 +457,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Подключение по Bluetooth"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Чтобы подключить клавиатуру к планшету, включите Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Включить"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Показывать без звука"</string>
+ <string name="block" msgid="2734508760962682611">"Блокировать все уведомления"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Показывать со звуком"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Не блокировать, показывать со звуком"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Показывать все настройки важности"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Блокировка"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Наименьшая важность"</string>
<string name="low_importance" msgid="4109929986107147930">"Низкая важность"</string>
<string name="default_importance" msgid="8192107689995742653">"Средняя важность"</string>
<string name="high_importance" msgid="1527066195614050263">"Высокая важность"</string>
<string name="max_importance" msgid="5089005872719563894">"Крайняя важность"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Не показывать эти уведомления."</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Показывать без звука в конце списка уведомлений"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Показывать без звука"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Показывать со звуком"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Показывать со звуком поверх всех окон"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Показывать со звуком в начале списка уведомлений и поверх всех окон"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Другие настройки"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Цвета и стиль"</string>
@@ -558,8 +546,7 @@
<item msgid="2139628951880142927">"Показывать процент во время зарядки (по умолчанию)"</item>
<item msgid="3327323682209964956">"Не показывать этот значок"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Другое"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Разделитель экрана"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Опустить"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Поднять"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 446590f..40daf19 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -75,7 +75,7 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Snímka obrazovky bola zaznamenaná."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Snímku obrazovky zobrazíte dotykom."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Snímku obrazovky sa nepodarilo zachytiť."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Snímku obrazovky nie je možné vytvoriť z dôvodu nedostatku miesta na úložisku."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Snímku obrazovky nie je možné vytvoriť z dôvodu nedostatku miesta v úložisku."</string>
<string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Vytváranie snímok obrazovky je zakázané aplikáciou alebo vašou organizáciou."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Možnosti prenosu súborov USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Pripojiť ako prehrávač médií (MTP)"</string>
@@ -209,8 +209,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Dlhší čas"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kratší čas"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Svietidlo je vypnuté."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Svietidlo nie je k dispozícii."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Svietidlo je zapnuté."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Svietidlo je vypnuté."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Svietidlo je zapnuté."</string>
@@ -458,34 +457,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnúť Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Ak chcete klávesnicu pripojiť k tabletu, najprv musíte zapnúť Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Zapnúť"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Zobrazovať upozornenia bez zvukového signálu"</string>
+ <string name="block" msgid="2734508760962682611">"Blokovať všetky upozornenia"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Nestíšiť"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Nestíšiť ani neblokovať"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Zobraziť nastavenia vysokej dôležitosti"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Zablokované"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Minimálna dôležitosť"</string>
<string name="low_importance" msgid="4109929986107147930">"Nízka dôležitosť"</string>
<string name="default_importance" msgid="8192107689995742653">"Normálna dôležitosť"</string>
<string name="high_importance" msgid="1527066195614050263">"Vysoká dôležitosť"</string>
<string name="max_importance" msgid="5089005872719563894">"Neodkladná dôležitosť"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Tieto upozornenia nikdy nezobrazovať"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Zobrazovať v dolnej časti zoznamu upozornení bez zvukového signálu"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Tieto upozornenia zobrazovať bez zvukového signálu"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Umožniť týmto upozorneniam vydávať zvukové signály"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Zobrazovať cez obrazovku a povoliť zvukový signál"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Zobrazovať v hornej časti zoznamu upozornení, zobrazovať cez obrazovku a povoliť zvukový signál"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Ďalšie nastavenia"</string>
<string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Farba a vzhľad"</string>
@@ -499,7 +487,7 @@
<string name="use_dark_theme" msgid="2900938704964299312">"Použiť tmavý motív pre systém Android OS"</string>
<string name="adjust_tint" msgid="3398569573231409878">"Upraviť tónovanie"</string>
<string name="adjust_brightness" msgid="980039329808178246">"Upraviť jas"</string>
- <string name="night_mode_disclaimer" msgid="598914896926759578">"V hlavných oblastiach systému Android OS (ako sú Nastavenia), ktoré sú obyčajne zobrazené v svetlom motíve, je použitý tmavý motív."</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"V hlavných oblastiach systému Android OS (ako sú Nastavenia), ktoré sú obyčajne zobrazené vo svetlom motíve, je použitý tmavý motív."</string>
<string name="color_apply" msgid="9212602012641034283">"Použiť"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Potvrdenie nastavení"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Niektoré nastavenia farieb môžu toto zariadenie znefunkčniť. Tieto nastavenia farieb potvrdíte kliknutím na tlačidlo OK, ináč sa tieto nastavenia o 10 sekúnd obnovia."</string>
@@ -558,8 +546,7 @@
<item msgid="2139628951880142927">"Zobrazovať percentá počas nabíjania (predvolené)"</item>
<item msgid="3327323682209964956">"Nezobrazovať túto ikonu"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Ďalšie"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Rozdeľovač obrazovky"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Posunúť nadol"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Posunúť nahor"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 327e553..991e9e2 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -208,8 +208,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Више времена."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Мање времена."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Батеријска лампа је искључена."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Лампа није доступна."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Батеријска лампа је укључена."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Батеријска лампа је искључена."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Батеријска лампа је укључена."</string>
@@ -457,34 +456,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Желите ли да укључите Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Да бисте повезали тастатуру са таблетом, прво морате да укључите Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Укључи"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Приказуј обавештења без звука"</string>
+ <string name="block" msgid="2734508760962682611">"Блокирај сва обавештења"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Не искључуј звук"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Не искључују звук нити блокирај"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Прикажи комплетна подешавања важности"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Блокирана"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Веома мала важност"</string>
<string name="low_importance" msgid="4109929986107147930">"Мала важност"</string>
<string name="default_importance" msgid="8192107689995742653">"Уобичајена важност"</string>
<string name="high_importance" msgid="1527066195614050263">"Велика важност"</string>
<string name="max_importance" msgid="5089005872719563894">"Важност: хитно"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Ова обавештења се никада не приказују"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Приказују се у дну листе обавештења без звука"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Ова обавештења се приказују без звука"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Дозволите да ова обавештења емитују звук"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Накратко се приказују на екрану и емитују звук"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Приказују се у врху листе обавештења, накратко се приказују на екрану и емитују звук"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Још подешавања"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Боја и изглед"</string>
@@ -557,8 +545,7 @@
<item msgid="2139628951880142927">"Прикажи проценат током пуњења (подразумевано)"</item>
<item msgid="3327323682209964956">"Не приказуј ову икону"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Друго"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Разделник подељеног екрана"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Помери надоле"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Помери нагоре"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index a23aba9..d35fad5 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Längre tid."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kortare tid."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Ficklampa av."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Ficklampan är inte tillgänglig."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Ficklampa på."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Ficklampan har inaktiverats."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Ficklampan har aktiverats."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vill du aktivera Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Om du vill ansluta tangentbordet till surfplattan måste du först aktivera Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivera"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Visa aviseringar utan ljud"</string>
+ <string name="block" msgid="2734508760962682611">"Blockera alla aviseringar"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Stäng inte av ljudet"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Stäng inte av ljudet och blockera inte"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Visa alla relevansinställningarna"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Blockerad"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Oviktig avisering"</string>
<string name="low_importance" msgid="4109929986107147930">"Oviktig avisering"</string>
<string name="default_importance" msgid="8192107689995742653">"Vanlig avisering"</string>
<string name="high_importance" msgid="1527066195614050263">"Viktig avisering"</string>
<string name="max_importance" msgid="5089005872719563894">"Brådskande avisering"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Visa aldrig de här aviseringarna"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Visa längst ned i listan, utan ljud"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Visa aviseringarna utan ljud"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Tillåt ljud för de här aviseringarna"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Visa med snabbtitt på skärmen och tillåt ljud"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Visa högst upp i aviseringslistan och med snabbtitt på skärmen samt tillåt ljud"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Fler inställningar"</string>
<string name="notification_done" msgid="5279426047273930175">"Klar"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Färg och utseende"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Visa procent under laddning (standard)"</item>
<item msgid="3327323682209964956">"Visa inte den här ikonen"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Annat"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Avdelare för delad skärm"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Flytta nedåt"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Flytta uppåt"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 4978d94..ddc1c0a 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -461,7 +461,7 @@
<string name="do_not_silence_block" msgid="4070647971382232311">"Usinyamazishe wala kuzuia"</string>
<string name="tuner_full_importance_settings" msgid="8103289238676424226">"Onyesha mipangilio kamili ya umuhimu"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Amezuiwa"</string>
- <string name="min_importance" msgid="1901894910809414782">"Umuhimu wa kiwango cha chini zaidi"</string>
+ <string name="min_importance" msgid="1901894910809414782">"Umuhimu wa kiwango cha chini"</string>
<string name="low_importance" msgid="4109929986107147930">"Umuhimu kiwango cha chini"</string>
<string name="default_importance" msgid="8192107689995742653">"Umuhimu wa kiwango cha kawaida"</string>
<string name="high_importance" msgid="1527066195614050263">"Umuhimu wa kiwango cha juu"</string>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 02a193a..66a1496 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -73,8 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"ஸ்கிரீன் ஷாட் எடுக்கப்பட்டது."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"உங்கள் ஸ்க்ரீன் ஷாட்டைப் பார்க்க தொடவும்."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"ஸ்க்ரீன் ஷாட்டை எடுக்க முடியவில்லை."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"போதுமான சேமிப்பிடம் இல்லாததால் ஸ்கிரீன் ஷாட்டைச் சேமிக்க முடியவில்லை."</string>
- <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"பயன்பாடு அல்லது உங்கள் நிறுவனம் ஸ்கிரீன் ஷாட்டுகளை எடுக்க அனுமதிக்கவில்லை."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"போதுமான சேமிப்பிடம் இல்லாததால் ஸ்கிரீன்ஷாட்டைச் சேமிக்க முடியவில்லை."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"பயன்பாடு அல்லது உங்கள் நிறுவனம் ஸ்கிரீன்ஷாட்டுகளை எடுக்க அனுமதிக்கவில்லை."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB கோப்பு இடமாற்ற விருப்பங்கள்"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"(MTP) மீடியா பிளேயராக ஏற்று"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"(PTP) கேமராவாக ஏற்று"</string>
@@ -306,7 +306,7 @@
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"பாதுகாப்புப் பயன்முறையில் <xliff:g id="APP">%s</xliff:g> முடக்கப்பட்டது."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"வரலாறு"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"அழி"</string>
- <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"பயன்பாடு பல சாளர அம்சத்தை ஆதரிக்காது"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"இந்தப் பயன்பாடு பல சாளர அம்சத்தை ஆதரிக்கவில்லை"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"பயன்பாடு பல சாளர அம்சத்தை ஆதரிக்காது"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"கிடைமட்டமாகப் பிரி"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"செங்குத்தாகப் பிரி"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 33a07ec..9b1ea74 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"เวลามากขึ้น"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"เวลาน้อยลง"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ไฟฉายปิดอยู่"</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ไฟฉายไม่พร้อมใช้งาน"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ไฟฉายเปิดอยู่"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ปิดไฟฉายแล้ว"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"เปิดไฟฉายแล้ว"</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"เปิดบลูทูธไหม"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"หากต้องการเชื่อมต่อแป้นพิมพ์กับแท็บเล็ต คุณต้องเปิดบลูทูธก่อน"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"เปิด"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"แสดงการแจ้งเตือนโดยไม่ส่งเสียง"</string>
+ <string name="block" msgid="2734508760962682611">"บล็อกการแจ้งเตือนทั้งหมด"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"ไม่ปิดเสียง"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"ไม่ปิดเสียงหรือบล็อก"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"แสดงการตั้งค่าความสำคัญแบบเต็ม"</string>
<string name="blocked_importance" msgid="5198578988978234161">"บล็อกแล้ว"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"ความสำคัญน้อย"</string>
<string name="low_importance" msgid="4109929986107147930">"ความสำคัญต่ำ"</string>
<string name="default_importance" msgid="8192107689995742653">"ความสำคัญปกติ"</string>
<string name="high_importance" msgid="1527066195614050263">"ความสำคัญสูง"</string>
<string name="max_importance" msgid="5089005872719563894">"ความสำคัญเร่งด่วน"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"ไม่ต้องแสดงการแจ้งเตือนเหล่านี้"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"แสดงที่ด้านล่างของรายการแจ้งเตือนโดยไม่ส่งเสียง"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"แสดงการแจ้งเตือนเหล่านี้โดยไม่ส่งเสียง"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"ให้การแจ้งเตือนเหล่านี้ส่งเสียงได้"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"แสดงบนหน้าจอและให้ส่งเสียงได้"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"แสดงที่ด้านบนของรายการการแจ้งเตือน แสดงบนหน้าจอและให้ส่งเสียงได้"</string>
<string name="notification_more_settings" msgid="816306283396553571">"การตั้งค่าเพิ่มเติม"</string>
<string name="notification_done" msgid="5279426047273930175">"เสร็จสิ้น"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"สีและลักษณะที่ปรากฏ"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"แสดงเปอร์เซ็นต์เมื่อชาร์จ (ค่าเริ่มต้น)"</item>
<item msgid="3327323682209964956">"อย่าแสดงไอคอนนี้"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"อื่นๆ"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"เส้นแบ่งหน้าจอ"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"เลื่อนลง"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"เลื่อนขึ้น"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 99fa7a2..d131c84 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Higit pang oras."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mas kaunting oras."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Naka-off ang flashlight."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Hindi available ang flashlight."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Naka-on ang flashlight."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Na-off ang flashlight."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Na-on ang flashlight."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"I-on ang Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Upang ikonekta ang iyong keyboard sa iyong tablet, kailangan mo munang i-on ang Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"I-on"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Tahimik na ipakita ang mga notification"</string>
+ <string name="block" msgid="2734508760962682611">"I-block ang lahat ng notification"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Huwag i-silent"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Huwag i-silent o i-block"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Ipakita ang kumpletong mga setting ng kahalagahan"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Na-block"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Hindi masyadong mahalaga"</string>
<string name="low_importance" msgid="4109929986107147930">"Hindi masyadong mahalaga"</string>
<string name="default_importance" msgid="8192107689995742653">"Mahalaga"</string>
<string name="high_importance" msgid="1527066195614050263">"Napakahalaga"</string>
<string name="max_importance" msgid="5089005872719563894">"Mahalagang-mahalaga"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Huwag kailanman ipakita ang mga notification na ito"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Tahimik na ipakita sa ibaba ng listahan ng notification"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Tahimik na ipakita ang mga notification na ito"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Payagan ang mga notification na ito na tumunog"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Palitawin sa screen at payagang tumunog"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Ipakita sa itaas ng listahan ng mga notification, palitawin sa screen at payagang tumunog"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Higit pang mga setting"</string>
<string name="notification_done" msgid="5279426047273930175">"Tapos Na"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Kulay at hitsura"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Ipakita ang porsyento kapag nagcha-charge (default)"</item>
<item msgid="3327323682209964956">"Huwag ipakita ang icon na ito"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Iba pa"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Divider ng split-screen"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Ilipat pababa"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Ilipat pataas"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 050f1f7..fd9e14c 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Daha uzun süre."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Daha kısa süre."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"El feneri kapalı."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"El feneri kullanılamıyor."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"El feneri açık."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"El feneri kapatıldı."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"El feneri açıldı."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth açılsın mı?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Klavyenizi tabletinize bağlamak için önce Bluetooth\'u açmanız gerekir."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aç"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Bildirimleri sessizce göster"</string>
+ <string name="block" msgid="2734508760962682611">"Tüm bildirimleri engelle"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Sessiz moda alma"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Sessiz moda alma veya engelleme"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Tüm önem ayarlarını göster"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Engellendi"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Önemi en düşük"</string>
<string name="low_importance" msgid="4109929986107147930">"Önem düzeyi düşük"</string>
<string name="default_importance" msgid="8192107689995742653">"Önem düzeyi normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Önem düzeyi yüksek"</string>
<string name="max_importance" msgid="5089005872719563894">"Önem düzeyi acil"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Bu bildirimleri hiçbir zaman gösterme"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Bildirim listesinin en altında sessizce göster"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Bu bildirimleri sessizce göster"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Bu bildirimlerin ses çıkarmasına izin ver"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Ekrana getir ve sesli bildirime izin ver"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Bildirim listesinin üstünde göster, ekrana getir ve sesli bildirime izin ver"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Diğer ayarlar"</string>
<string name="notification_done" msgid="5279426047273930175">"Bitti"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Renk ve görünüm"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Şarj olurken yüzdeyi göster (varsayılan)"</item>
<item msgid="3327323682209964956">"Bu simgeyi gösterme"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Diğer"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Bölünmüş ekran ayırıcı"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Aşağı taşı"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Yukarı taşı"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 485e2b2..e5bf06d 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -209,8 +209,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Більше часу."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Менше часу."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Ліхтарик вимк."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Ліхтарик недоступний."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Ліхтарик увімк."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Ліхтарик вимкнено."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Ліхтарик увімкнено."</string>
@@ -458,34 +457,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Увімкнути Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Щоб під’єднати клавіатуру до планшета, спершу потрібно ввімкнути Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Увімкнути"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Показувати сповіщення без звукового сигналу"</string>
+ <string name="block" msgid="2734508760962682611">"Блокувати всі сповіщення"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Не вимикати звуковий сигнал"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Не вимикати звуковий сигнал і не блокувати"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Показати налаштування пріоритетності"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Заблоковано"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Низький пріоритет"</string>
<string name="low_importance" msgid="4109929986107147930">"Низький пріоритет"</string>
<string name="default_importance" msgid="8192107689995742653">"Стандартний пріоритет"</string>
<string name="high_importance" msgid="1527066195614050263">"Високий пріоритет"</string>
<string name="max_importance" msgid="5089005872719563894">"Терміново"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Ніколи не показувати ці сповіщення"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Показувати сповіщення внизу списку без звукового сигналу"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Показувати ці сповіщення без звукового сигналу"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Увімкнути звуковий сигнал для цих сповіщень"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Показувати сповіщення на екрані зі звуковим сигналом"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Показувати сповіщення вгорі списку, на екрані та зі звуковим сигналом"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Більше налаштувань"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Колір і вигляд"</string>
@@ -558,8 +546,7 @@
<item msgid="2139628951880142927">"Показувати відсотки під час заряджання (за умовчанням)"</item>
<item msgid="3327323682209964956">"Не показувати цей значок"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Інше"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Розділювач екрана"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Перемістити вниз"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Перемістити вгору"</string>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 20a2a6f..7a10732 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"مزید وقت۔"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"کم وقت۔"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"فلیش لائٹ آف ہے۔"</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"فلیش لائٹ دستیاب نہیں ہے"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"فلیش لائٹ آن ہے۔"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"فلیش لائٹ کو آف کر دیا گیا۔"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"فلیش لائٹ کو آن کر دیا گیا۔"</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"بلوٹوتھ آن کریں؟"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"اپنے کی بورڈ کو اپنے ٹیبلٹ کے ساتھ منسلک کرنے کیلئے پہلے آپ کو اپنا بلو ٹوتھ آن کرنا ہو گا۔"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"آن کریں"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"اطلاعات خاموشی سے دکھائیں"</string>
+ <string name="block" msgid="2734508760962682611">"تمام اطلاعات کو مسدود کریں"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"خاموش نہ کریں"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"خاموش یا مسدود نہ کریں"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"اہمیت کی پوری ترتیبات دکھائیں"</string>
<string name="blocked_importance" msgid="5198578988978234161">"مسدود کردہ"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"کم سے کم اہمیت"</string>
<string name="low_importance" msgid="4109929986107147930">"کم اہمیت"</string>
<string name="default_importance" msgid="8192107689995742653">"عمومی اہمیت"</string>
<string name="high_importance" msgid="1527066195614050263">"زیادہ اہمیت"</string>
<string name="max_importance" msgid="5089005872719563894">"فوری اہمیت"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"یہ اطلاعات کبھی مت دکھائیں"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"اطلاعات کی فہرست کے سب سے نیچے خاموشی سے دکھائیں"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"خاموشی سے یہ اطلاعات دکھائیں"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"ان اطلاعات کو آواز نکالنے کی اجازت دیں"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"اسکرین پر دکھائیں اور آواز کی اجازت دیں"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"اطلاعات کی فہرست پر سب سے اوپر دکھائیں، اسکرین پر دکھائیں اور آواز کی اجازت دیں"</string>
<string name="notification_more_settings" msgid="816306283396553571">"مزید ترتیبات"</string>
<string name="notification_done" msgid="5279426047273930175">"ہوگیا"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"رنگ اور ظہور"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"چارج ہوتے وقت فیصد دکھائیں (ڈیفالٹ)"</item>
<item msgid="3327323682209964956">"یہ آئیکن نہ دکھائیں"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"دیگر"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"سپلٹ اسکرین تقسیم کار"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"نیچے منتقل کریں"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"اوپر منتقل کریں"</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 3fc7aad..79729dc 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Ko‘proq vaqt."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kamroq vaqt."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Fonar o‘chirilgan."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Bu yerda fonar yo‘q."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Fonar yoqilgan."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Fonar o‘chirildi."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Fonar yoqildi."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth yoqilsinmi?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviaturani planshetingizga ulash uchun Bluetooth xizmatini yoqishingiz kerak."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Yoqish"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Bildirishnomalar ovozsiz ko‘rsatilsin"</string>
+ <string name="block" msgid="2734508760962682611">"Barcha bildirishnomalar bloklansin"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Ovozi o‘chirilmasin"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Ovozi o‘chirilmasin yoki bloklanmasin"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Barcha muhimlik sozlamalarini ko‘rsatish"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Bloklangan"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Kamroq muhim"</string>
<string name="low_importance" msgid="4109929986107147930">"Kamroq muhim"</string>
<string name="default_importance" msgid="8192107689995742653">"O‘rtacha muhim"</string>
<string name="high_importance" msgid="1527066195614050263">"Juda muhim"</string>
<string name="max_importance" msgid="5089005872719563894">"Favqulodda muhim"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Bu bildirishnomalar boshqa ko‘rsatilmasin"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Bildirishnomalar ro‘yxatining oxirida ovozsiz ko‘rsatilsin"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Bu bildirishnomalar ovozsiz ko‘rsatilsin"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Bu bildirishnomalar ovoz bilan ko‘rsatilsin"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Barcha oynalar ustida ovoz bilan ko‘rsatilsin"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Bildirishnomalar ro‘yxatining boshida va barcha oynalar ustida ovoz bilan ko‘rsatilsin"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Boshqa sozlamalar"</string>
<string name="notification_done" msgid="5279426047273930175">"Tayyor"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Rang va ko‘rinishi"</string>
@@ -497,7 +485,7 @@
<string name="use_dark_theme" msgid="2900938704964299312">"Android uchun to‘q rangli mavzudan foydalanish"</string>
<string name="adjust_tint" msgid="3398569573231409878">"Rang tusini o‘zgartirish"</string>
<string name="adjust_brightness" msgid="980039329808178246">"Yorqinlikni o‘zgartirish"</string>
- <string name="night_mode_disclaimer" msgid="598914896926759578">"To‘q rangli mavzu Android OS’ning o‘zak sahifalariga ham qo‘llaniladi va bu Sozlamalar kabi och rangli mavzularda odatdagiday ko‘rsatiladi."</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"To‘q rangli mavzu Android tizimining odatda och rangda ko‘rsatiladigan o‘zak sahifalariga (masalan, Sozlamalar) nisbatan qo‘llaniladi."</string>
<string name="color_apply" msgid="9212602012641034283">"Qo‘llash"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Sozlamalarni tasdiqlang"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Ba’zi rang sozlamalari qurilmadan foydalanishni qiyinlashtirish mumkin. Tanlgan parametrlarni tasdiqlash uchun “OK” tugmasini bosing. Aks holda, ular 10 soniyadan so‘ng qayta tiklanadi."</string>
@@ -556,9 +544,8 @@
<item msgid="2139628951880142927">"Quvvat olayotganda foizda ko‘rsatilsin (birlamchi)"</item>
<item msgid="3327323682209964956">"Bu belgi boshqa ko‘rsatilmasin"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
- <string name="accessibility_divider" msgid="5903423481953635044">"Ekranni ikkiga bo‘lgich"</string>
+ <string name="other" msgid="4060683095962566764">"Boshqa"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"Ekranni ikkiga bo‘lish chizig‘i"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pastga siljitish"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Tepaga siljitish"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Chapga siljitish"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index e8babe5..074a8a0 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -303,8 +303,7 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"khóa màn hình"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"tìm kiếm"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Không thể khởi động <xliff:g id="APP">%s</xliff:g>."</string>
- <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
- <skip />
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> bị tắt ở chế độ an toàn."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Lịch sử"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Xóa"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ứng dụng này không hỗ trợ chế độ nhiều cửa sổ"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index d48a9e6..dd5ea1f 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"延长时间。"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"缩短时间。"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"手电筒关闭。"</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"无法使用手电筒。"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"手电筒打开。"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"手电筒已关闭。"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"手电筒已打开。"</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"要开启蓝牙吗?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"要将您的键盘连接到平板电脑,您必须先开启蓝牙。"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"开启"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"显示通知,但不发出提示音"</string>
+ <string name="block" msgid="2734508760962682611">"屏蔽所有通知"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"不静音"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"不静音也不屏蔽"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"显示完整的重要性设置"</string>
<string name="blocked_importance" msgid="5198578988978234161">"屏蔽"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"重要性最低"</string>
<string name="low_importance" msgid="4109929986107147930">"重要性:低"</string>
<string name="default_importance" msgid="8192107689995742653">"重要性:一般"</string>
<string name="high_importance" msgid="1527066195614050263">"重要性:高"</string>
<string name="max_importance" msgid="5089005872719563894">"重要性:紧急"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"一律不显示这些通知"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"在通知列表底部显示,但不发出提示音"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"显示这些通知,但不发出提示音"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"允许这些通知发出提示音"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"在屏幕上短暂显示,并允许发出提示音"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"在通知列表顶部显示,同时在屏幕上短暂显示,并允许发出提示音"</string>
<string name="notification_more_settings" msgid="816306283396553571">"更多设置"</string>
<string name="notification_done" msgid="5279426047273930175">"完成"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"颜色和外观"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"充电时显示百分比(默认)"</item>
<item msgid="3327323682209964956">"不显示此图标"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"其他"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"分屏分隔线"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"下移"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"上移"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 609f94d..bd379b7 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"增加時間。"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"減少時間。"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"閃光燈已關閉。"</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"無法使用手電筒。"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"閃光燈已開啟。"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"閃光燈已關閉。"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"閃光燈已開啟。"</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙嗎?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連接至平板電腦,請先開啟藍牙。"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"開啟"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"顯示通知,但不發出音效"</string>
+ <string name="block" msgid="2734508760962682611">"封鎖所有通知"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"不設為靜音"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"不設為靜音或封鎖"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"顯示所有重要性設定"</string>
<string name="blocked_importance" msgid="5198578988978234161">"已封鎖"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"最低重要性"</string>
<string name="low_importance" msgid="4109929986107147930">"低重要性"</string>
<string name="default_importance" msgid="8192107689995742653">"一般重要性"</string>
<string name="high_importance" msgid="1527066195614050263">"高重要性"</string>
<string name="max_importance" msgid="5089005872719563894">"緊急重要性"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"永不顯示這些通知"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"在通知清單底部顯示但不發出音效"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"顯示這些通知但不發出音效"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"允許這些通知發出音效"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"不時於螢幕出現並發出音效"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"在通知清單頂部顯示,並不時於螢幕出現及發出音效"</string>
<string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
<string name="notification_done" msgid="5279426047273930175">"完成"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"顏色和外觀"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"充電時顯示百分比 (預設)"</item>
<item msgid="3327323682209964956">"不顯示這個圖示"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"其他"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"分割畫面分隔線"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"向下移"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"向上移"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 2188c3c..d580b28 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"增加時間。"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"減少時間。"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"閃光燈已關閉。"</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"無法使用手電筒。"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"閃光燈已開啟。"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"閃光燈已關閉。"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"閃光燈已開啟。"</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙功能嗎?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連線到平板電腦,您必須先開啟藍牙。"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"開啟"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"顯示通知,但不發出任何音效"</string>
+ <string name="block" msgid="2734508760962682611">"封鎖所有通知"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"不設定靜音"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"不設定靜音或封鎖"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"顯示完整的重要性設定"</string>
<string name="blocked_importance" msgid="5198578988978234161">"封鎖"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"最低重要性"</string>
<string name="low_importance" msgid="4109929986107147930">"低重要性"</string>
<string name="default_importance" msgid="8192107689995742653">"一般重要性"</string>
<string name="high_importance" msgid="1527066195614050263">"高重要性"</string>
<string name="max_importance" msgid="5089005872719563894">"緊急重要性"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"一律不顯示這些通知"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"顯示在通知清單底端,但不發出任何音效"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"顯示這些通知,但不發出任何音效"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"允許這些通知發出音效"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"短暫顯示在畫面上並發出音效"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"顯示在通知清單頂端,同時短暫顯示在畫面上並發出音效"</string>
<string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
<string name="notification_done" msgid="5279426047273930175">"完成"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"顏色和外觀"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"充電時顯示百分比 (預設)"</item>
<item msgid="3327323682209964956">"不顯示這個圖示"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"其他"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"分割畫面分隔線"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"向下移"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"向上移"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 69c85ab..9382b26 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -207,8 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Isikhathi esiningi."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Isikhathi esincane."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"I-Flashlight ivaliwe."</string>
- <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
- <skip />
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"I-Flashlight ayitholakali."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"I-Flashlight ivuliwe."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"I-Flashlight ivaliwe."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"I-Flashlight ivuliwe."</string>
@@ -456,34 +455,23 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vula i-Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Ukuze uxhume ikhibhodi yakho nethebhulethi yakho, kufanele uqale ngokuvula i-Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Vula"</string>
- <!-- no translation found for show_silently (6841966539811264192) -->
- <skip />
- <!-- no translation found for block (2734508760962682611) -->
- <skip />
- <!-- no translation found for do_not_silence (6878060322594892441) -->
- <skip />
- <!-- no translation found for do_not_silence_block (4070647971382232311) -->
- <skip />
- <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
- <skip />
+ <string name="show_silently" msgid="6841966539811264192">"Bonisa izaziso ngokuthulile"</string>
+ <string name="block" msgid="2734508760962682611">"Vimbela zonke izaziso"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Ungathulisi"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Ungathulisi noma uvimbele"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Bonisa izilungiselelo ezibalulekile ezigcwele"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Kuvinjelwe"</string>
- <!-- no translation found for min_importance (1901894910809414782) -->
- <skip />
+ <string name="min_importance" msgid="1901894910809414782">"Okubaluleke kancane"</string>
<string name="low_importance" msgid="4109929986107147930">"Ukubaluleka okuphansi"</string>
<string name="default_importance" msgid="8192107689995742653">"Ukubaluleka okujwayelekile"</string>
<string name="high_importance" msgid="1527066195614050263">"Ukubaluleka okuphezulu"</string>
<string name="max_importance" msgid="5089005872719563894">"Ukubaluleka okusheshayo"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Ungalokothi ubonise lezi zaziso"</string>
- <!-- no translation found for notification_importance_min (1938190340516905748) -->
- <skip />
- <!-- no translation found for notification_importance_low (3657252049508213048) -->
- <skip />
- <!-- no translation found for notification_importance_default (4466466472622442175) -->
- <skip />
- <!-- no translation found for notification_importance_high (2135428926525093825) -->
- <skip />
- <!-- no translation found for notification_importance_max (5806278962376556491) -->
- <skip />
+ <string name="notification_importance_min" msgid="1938190340516905748">"Bonisa ngokuthulile ngaphansi kohlu lwesaziso"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Bonisa ngokuthulile lezi zaziso"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Vumela lezi zaziso ukwenza umsindo"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Beka kusikrini futhi uvumele umsindo"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Bonisa phezulu kohlu lwezaziso, beka phezu kwesikrini futhi uvumele umsindo"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Izilungiselelo eziningi"</string>
<string name="notification_done" msgid="5279426047273930175">"Kwenziwe"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Umbala nokubonakala"</string>
@@ -556,8 +544,7 @@
<item msgid="2139628951880142927">"Bonisa iphesentheji uma ishaja (okuzenzakalelayo)"</item>
<item msgid="3327323682209964956">"Ungabonisi lesi sithonjana"</item>
</string-array>
- <!-- no translation found for other (4060683095962566764) -->
- <skip />
+ <string name="other" msgid="4060683095962566764">"Okunye"</string>
<string name="accessibility_divider" msgid="5903423481953635044">"Isihlukanisi sokuhlukanisa isikrini"</string>
<string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Iya phansi"</string>
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Iya phezulu"</string>
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/ids.xml b/packages/SystemUI/res/values/ids.xml
index b9eee2e..9697ea6 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -48,6 +48,7 @@
<item type="id" name="transformation_start_y_tag"/>
<item type="id" name="transformation_start_scale_x_tag"/>
<item type="id" name="transformation_start_scale_y_tag"/>
+ <item type="id" name="custom_background_color"/>
<!-- Whether the icon is from a notification for which targetSdk < L -->
<item type="id" name="icon_is_pre_L"/>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index 4f382ea..c7fb0ec 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -30,12 +30,14 @@
<!-- Button to close PIP overlay menu on PIP UI -->
<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>
-
+ <string name="pip_hold_home" translatable="false">Hold <b>HOME</b> 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/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 913b2b3..2e94bc7 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -23,7 +23,6 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.shortcut.ShortcutKeyDispatcher;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -72,8 +71,8 @@
}
public ScrimController createScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
- View headsUpScrim, boolean scrimSrcEnabled) {
- return new ScrimController(scrimBehind, scrimInFront, headsUpScrim, scrimSrcEnabled);
+ View headsUpScrim) {
+ return new ScrimController(scrimBehind, scrimInFront, headsUpScrim);
}
public <T> T createInstance(Class<T> classType) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index f39f302..ab612dd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -16,8 +16,10 @@
package com.android.systemui.media;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.Cursor;
import android.media.AudioAttributes;
import android.media.IAudioService;
import android.media.IRingtonePlayer;
@@ -25,15 +27,20 @@
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.provider.MediaStore;
+import android.provider.MediaStore.Audio.AudioColumns;
import android.util.Log;
+import com.android.internal.util.Preconditions;
import com.android.systemui.SystemUI;
import java.io.FileDescriptor;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
@@ -180,6 +187,34 @@
return Ringtone.getTitle(getContextForUser(user), uri,
false /*followSettingsUri*/, false /*allowRemote*/);
}
+
+ @Override
+ public ParcelFileDescriptor openRingtone(Uri uri) {
+ final UserHandle user = Binder.getCallingUserHandle();
+ final ContentResolver resolver = getContextForUser(user).getContentResolver();
+
+ // Only open the requested Uri if it's a well-known ringtone or
+ // other sound from the platform media store, otherwise this opens
+ // up arbitrary access to any file on external storage.
+ if (uri.toString().startsWith(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString())) {
+ try (Cursor c = resolver.query(uri, new String[] {
+ MediaStore.Audio.AudioColumns.IS_RINGTONE,
+ MediaStore.Audio.AudioColumns.IS_ALARM,
+ MediaStore.Audio.AudioColumns.IS_NOTIFICATION
+ }, null, null, null)) {
+ if (c.moveToFirst()) {
+ if (c.getInt(0) != 0 || c.getInt(1) != 0 || c.getInt(2) != 0) {
+ try {
+ return resolver.openFileDescriptor(uri, "r");
+ } catch (IOException e) {
+ throw new SecurityException(e);
+ }
+ }
+ }
+ }
+ }
+ throw new SecurityException("Uri is not ringtone, alarm, or notification: " + uri);
+ }
};
private Context getContextForUser(UserHandle user) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 2c5cb89..24b45cc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -77,7 +77,9 @@
@Override
public int getOffsetTop(TileRecord tile) {
- return ((ViewGroup) tile.tileView.getParent()).getTop() + getTop();
+ final ViewGroup parent = (ViewGroup) tile.tileView.getParent();
+ if (parent == null) return 0;
+ return parent.getTop() + getTop();
}
@Override
@@ -165,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..5b05e84 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
+import android.graphics.Point;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
@@ -26,7 +27,9 @@
import android.widget.FrameLayout;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.statusbar.phone.BaseStatusBarHeader;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.stack.StackStateAnimator;
@@ -39,6 +42,8 @@
private static final String TAG = "QSContainer";
private static final boolean DEBUG = false;
+ private final Point mSizePoint = new Point();
+
private int mHeightOverride = -1;
private QSPanel mQSPanel;
private QSDetail mQSDetail;
@@ -51,6 +56,8 @@
private long mDelay;
private QSAnimator mQSAnimator;
+ private QSCustomizer mQSCustomizer;
+ private NotificationPanelView mPanelView;
public QSContainer(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -65,21 +72,33 @@
mHeader = (BaseStatusBarHeader) findViewById(R.id.header);
mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel),
mQSPanel);
+ mQSCustomizer = (QSCustomizer) findViewById(R.id.qs_customize);
+ mQSCustomizer.setQsContainer(this);
}
public void setHost(QSTileHost qsh) {
- mQSPanel.setHost(qsh);
+ mQSPanel.setHost(qsh, mQSCustomizer);
mHeader.setQSPanel(mQSPanel);
mQSDetail.setHost(qsh);
mQSAnimator.setHost(qsh);
}
+ public void setPanelView(NotificationPanelView panelView) {
+ mPanelView = panelView;
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Since we control our own bottom, be whatever size we want.
// Otherwise the QSPanel ends up with 0 height when the window is only the
// size of the status bar.
super.onMeasure(widthMeasureSpec, MeasureSpec.UNSPECIFIED);
+
+ // QSCustomizer is always be the height of the screen, but do this after
+ // other measuring to avoid changing the height of the QSContainer.
+ getDisplay().getRealSize(mSizePoint);
+ mQSCustomizer.measure(widthMeasureSpec,
+ MeasureSpec.makeMeasureSpec(mSizePoint.y, MeasureSpec.EXACTLY));
}
@Override
@@ -88,6 +107,10 @@
updateBottom();
}
+ public boolean isCustomizing() {
+ return mQSCustomizer.isCustomizing();
+ }
+
/**
* Overrides the height of this view (post-layout), so that the content is clipped to that
* height and the background is set to that height.
@@ -104,6 +127,9 @@
* during closing the detail panel, this already returns the smaller height.
*/
public int getDesiredHeight() {
+ if (isCustomizing()) {
+ return getHeight();
+ }
if (mQSDetail.isClosingDetail()) {
return mQSPanel.getGridHeight() + mHeader.getCollapsedHeight() + getPaddingBottom();
} else {
@@ -111,9 +137,18 @@
}
}
+ public void notifyCustomizeChanged() {
+ // The customize state changed, so our height changed.
+ updateBottom();
+ // Let the panel know the position changed and it needs to update where notifications
+ // and whatnot are.
+ mPanelView.onQsHeightChanged();
+ }
+
private void updateBottom() {
int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
- int height = (int) (mQsExpansion * (heightOverride - mHeader.getCollapsedHeight()))
+ int height = mQSCustomizer.isCustomizing() ? mQSCustomizer.getHeight()
+ : (int) (mQsExpansion * (heightOverride - mHeader.getCollapsedHeight()))
+ mHeader.getCollapsedHeight();
setBottom(getTop() + height);
mQSDetail.setBottom(getTop() + height);
@@ -138,6 +173,10 @@
return mQSPanel;
}
+ public QSCustomizer getCustomizer() {
+ return mQSCustomizer;
+ }
+
public boolean isShowingDetail() {
return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail();
}
@@ -156,6 +195,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/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 71c1913..899b0ef 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -155,12 +155,6 @@
return mHost.createTile(subPanel);
}
- protected void createCustomizePanel() {
- mCustomizePanel = (QSCustomizer) LayoutInflater.from(mContext)
- .inflate(R.layout.qs_customize_panel, null);
- mCustomizePanel.setHost(mHost);
- }
-
public void setBrightnessMirror(BrightnessMirrorController c) {
super.onFinishInflate();
ToggleSlider brightnessSlider = (ToggleSlider) findViewById(R.id.brightness_slider);
@@ -173,12 +167,15 @@
mCallback = callback;
}
- public void setHost(QSTileHost host) {
+ public void setHost(QSTileHost host, QSCustomizer customizer) {
mHost = host;
mHost.addCallback(this);
setTiles(mHost.getTiles());
mFooter.setHost(host);
- createCustomizePanel();
+ mCustomizePanel = customizer;
+ if (mCustomizePanel != null) {
+ mCustomizePanel.setHost(mHost);
+ }
}
public QSTileHost getHost() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 8b826ee..d0e034b 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,8 +56,15 @@
}
@Override
- protected void createCustomizePanel() {
- // No customizing from the header.
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ TunerService.get(mContext).addTunable(mNumTiles, NUM_QUICK_TILES);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ TunerService.get(mContext).removeTunable(mNumTiles);
}
public void setQSPanelAndHeader(QSPanel fullPanel, View header) {
@@ -86,6 +97,7 @@
public void setMaxTiles(int maxTiles) {
mMaxTiles = maxTiles;
+ setTiles(mHost.getTiles());
}
@Override
@@ -114,6 +126,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..068efa6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -32,8 +32,10 @@
import android.widget.Toolbar;
import android.widget.Toolbar.OnMenuItemClickListener;
import com.android.systemui.R;
+import com.android.systemui.qs.QSContainer;
import com.android.systemui.qs.QSDetailClipper;
import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.QSTileHost;
@@ -59,6 +61,9 @@
private RecyclerView mRecyclerView;
private TileAdapter mTileAdapter;
private Toolbar mToolbar;
+ private boolean mCustomizing;
+ private NotificationsQuickSettingsContainer mNotifQsContainer;
+ private QSContainer mQsContainer;
public QSCustomizer(Context context, AttributeSet attrs) {
super(new ContextThemeWrapper(context, android.R.style.Theme_Material), attrs);
@@ -70,6 +75,14 @@
mPhoneStatusBar = host.getPhoneStatusBar();
}
+ public void setContainer(NotificationsQuickSettingsContainer notificationsQsContainer) {
+ mNotifQsContainer = notificationsQsContainer;
+ }
+
+ public void setQsContainer(QSContainer qsContainer) {
+ mQsContainer = qsContainer;
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -87,6 +100,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());
@@ -104,23 +118,31 @@
public void show(int x, int y) {
if (!isShown) {
isShown = true;
- mPhoneStatusBar.getStatusBarWindow().addView(this);
setTileSpecs();
- mClipper.animateCircularClip(x, y, true, null);
+ setVisibility(View.VISIBLE);
+ mClipper.animateCircularClip(x, y, true, mExpandAnimationListener);
new TileQueryHelper(mContext, mHost).setListener(mTileAdapter);
+ mNotifQsContainer.setCustomizerAnimating(true);
}
}
public void hide(int x, int y) {
if (isShown) {
isShown = false;
+ setCustomizing(false);
save();
mClipper.animateCircularClip(x, y, false, mCollapseAnimationListener);
+ mNotifQsContainer.setCustomizerAnimating(true);
}
}
+ private void setCustomizing(boolean customizing) {
+ mCustomizing = customizing;
+ mQsContainer.notifyCustomizeChanged();
+ }
+
public boolean isCustomizing() {
- return isShown;
+ return mCustomizing;
}
@Override
@@ -154,19 +176,34 @@
mTileAdapter.saveSpecs(mHost);
}
+ private final AnimatorListener mExpandAnimationListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ setCustomizing(true);
+ mNotifQsContainer.setCustomizerAnimating(false);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mNotifQsContainer.setCustomizerAnimating(false);
+ }
+ };
+
private final AnimatorListener mCollapseAnimationListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (!isShown) {
- mPhoneStatusBar.getStatusBarWindow().removeView(QSCustomizer.this);
+ setVisibility(View.GONE);
}
+ mNotifQsContainer.setCustomizerAnimating(false);
}
@Override
public void onAnimationCancel(Animator animation) {
if (!isShown) {
- mPhoneStatusBar.getStatusBarWindow().removeView(QSCustomizer.this);
+ setVisibility(View.GONE);
}
+ mNotifQsContainer.setCustomizerAnimating(false);
}
};
}
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 39d1447..2e87525 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -172,6 +172,7 @@
}
private void postBindView() {
+ if (mCurrentView == null) return;
mCurrentView.post(new Runnable() {
@Override
public void run() {
@@ -181,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/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index f5ae351..efac0fb3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -35,9 +35,11 @@
import android.util.Log;
import android.view.Display;
import android.view.View;
+import android.widget.Toast;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
+import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SystemUI;
import com.android.systemui.recents.events.EventBus;
@@ -393,28 +395,35 @@
boolean screenPinningActive = ssp.isScreenPinningActive();
boolean isTopTaskHome = topTask != null && SystemServicesProxy.isHomeStack(topTask.stackId);
if (topTask != null && !isTopTaskHome && !screenPinningActive) {
- if (sSystemServicesProxy.isSystemUser(currentUser)) {
- mImpl.dockTopTask(topTask.id, dragMode, stackCreateMode, initialBounds);
- } else {
- if (mSystemToUserCallbacks != null) {
- IRecentsNonSystemUserCallbacks callbacks =
- mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
- if (callbacks != null) {
- try {
- callbacks.dockTopTask(topTask.id, dragMode, stackCreateMode,
- initialBounds);
- } catch (RemoteException e) {
- Log.e(TAG, "Callback failed", e);
+ if (topTask.isDockable) {
+ if (sSystemServicesProxy.isSystemUser(currentUser)) {
+ mImpl.dockTopTask(topTask.id, dragMode, stackCreateMode, initialBounds);
+ } else {
+ if (mSystemToUserCallbacks != null) {
+ IRecentsNonSystemUserCallbacks callbacks =
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ if (callbacks != null) {
+ try {
+ callbacks.dockTopTask(topTask.id, dragMode, stackCreateMode,
+ initialBounds);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
+ }
+ } else {
+ Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
}
- } else {
- Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
}
}
+ mDraggingInRecentsCurrentUser = currentUser;
+ return true;
+ } else {
+ Toast.makeText(mContext, R.string.recents_drag_non_dockable_task_message,
+ Toast.LENGTH_SHORT).show();
+ return false;
}
- mDraggingInRecentsCurrentUser = currentUser;
- return true;
+ } else {
+ return false;
}
- return false;
}
@Override
@@ -513,8 +522,9 @@
* Handle Recents activity visibility changed.
*/
public final void onBusEvent(final RecentsVisibilityChangedEvent event) {
- int processUser = event.systemServicesProxy.getProcessUser();
- if (event.systemServicesProxy.isSystemUser(processUser)) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ int processUser = ssp.getProcessUser();
+ if (ssp.isSystemUser(processUser)) {
mImpl.onVisibilityChanged(event.applicationContext, event.visible);
} else {
postToSystemUser(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index c41098f..cd1a27f 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;
@@ -54,7 +55,7 @@
import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
import com.android.systemui.recents.events.activity.LaunchTaskSucceededEvent;
import com.android.systemui.recents.events.activity.ShowHistoryEvent;
-import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
+import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
@@ -96,6 +97,7 @@
private long mLastTabKeyEventTime;
private boolean mFinishedOnStartup;
private boolean mIgnoreAltTabRelease;
+ private boolean mIsVisible;
// Top level views
private RecentsView mRecentsView;
@@ -107,7 +109,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 +121,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 +129,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;
}
@@ -173,59 +175,6 @@
}
};
- /** Updates the set of recent tasks */
- void updateRecentsTasks() {
- // If AlternateRecentsComponent has preloaded a load plan, then use that to prevent
- // reconstructing the task stack
- RecentsTaskLoader loader = Recents.getTaskLoader();
- RecentsTaskLoadPlan plan = RecentsImpl.consumeInstanceLoadPlan();
- if (plan == null) {
- plan = loader.createLoadPlan(this);
- }
-
- // Start loading tasks according to the load plan
- RecentsConfiguration config = Recents.getConfiguration();
- RecentsActivityLaunchState launchState = config.getLaunchState();
- if (!plan.hasTasks()) {
- loader.preloadTasks(plan, -1, launchState.launchedFromHome);
- }
- RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
- loadOpts.runningTaskId = launchState.launchedToTaskId;
- loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
- loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
- loader.loadTasks(this, plan, loadOpts);
-
- TaskStack stack = plan.getTaskStack();
- mRecentsView.setTaskStack(stack);
-
- // Animate the SystemUI scrims into view
- Task launchTarget = stack.getLaunchTarget();
- int taskCount = stack.getTaskCount();
- int launchTaskIndexInStack = launchTarget != null
- ? stack.indexOfStackTask(launchTarget)
- : 0;
- boolean hasNavBarScrim = (taskCount > 0) && !config.hasTransposedNavBar;
- boolean animateNavBarScrim = !launchState.launchedWhileDocking;
- mScrimViews.prepareEnterRecentsAnimation(hasNavBarScrim, animateNavBarScrim);
-
- // Keep track of whether we launched from the nav bar button or via alt-tab
- if (launchState.launchedWithAltTab) {
- MetricsLogger.count(this, "overview_trigger_alttab", 1);
- } else {
- MetricsLogger.count(this, "overview_trigger_nav_btn", 1);
- }
- // Keep track of whether we launched from an app or from home
- if (launchState.launchedFromAppWithThumbnail) {
- 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);
- } else {
- MetricsLogger.count(this, "overview_source_home", 1);
- }
- // Keep track of the total stack task count
- MetricsLogger.histogram(this, "overview_task_count", taskCount);
- }
-
/**
* Dismisses the history view back into the stack view.
*/
@@ -294,12 +243,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() {
@@ -348,6 +293,7 @@
// Set the Recents layout
setContentView(R.layout.recents);
+ takeKeyEvents(true);
mRecentsView = (RecentsView) findViewById(R.id.recents_view);
mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
@@ -365,11 +311,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) {
@@ -386,45 +331,12 @@
}
@Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- setIntent(intent);
- }
-
- @Override
protected void onStart() {
super.onStart();
- // Update the recent tasks
- updateRecentsTasks();
-
- // If this is a new instance from a configuration change, then we have to manually trigger
- // the enter animation state, or if recents was relaunched by AM, without going through
- // the normal mechanisms
- RecentsConfiguration config = Recents.getConfiguration();
- RecentsActivityLaunchState launchState = config.getLaunchState();
- boolean wasLaunchedByAm = !launchState.launchedFromHome &&
- !launchState.launchedFromAppWithThumbnail;
- if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
- EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
- }
-
// Notify that recents is now visible
- SystemServicesProxy ssp = Recents.getSystemServices();
- EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
-
+ EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true));
MetricsLogger.visible(this, MetricsEvent.OVERVIEW_ACTIVITY);
-
- mRecentsView.getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
-
- @Override
- public boolean onPreDraw() {
- mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
- EventBus.getDefault().post(new RecentsDrawnEvent());
- return true;
- }
- });
}
@Override
@@ -434,26 +346,91 @@
}
@Override
- protected void onPause() {
- super.onPause();
+ protected void onResume() {
+ super.onResume();
- // Stop the fast-toggle dozer
- mIterateTrigger.stopDozing();
+ // If the Recents component has preloaded a load plan, then use that to prevent
+ // reconstructing the task stack
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ RecentsTaskLoadPlan loadPlan = RecentsImpl.consumeInstanceLoadPlan();
+ if (loadPlan == null) {
+ loadPlan = loader.createLoadPlan(this);
+ }
+
+ // Start loading tasks according to the load plan
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ if (!loadPlan.hasTasks()) {
+ loader.preloadTasks(loadPlan, -1, launchState.launchedFromHome);
+ }
+
+ RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+ loadOpts.runningTaskId = launchState.launchedToTaskId;
+ loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
+ loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
+ loader.loadTasks(this, loadPlan, loadOpts);
+ TaskStack stack = loadPlan.getTaskStack();
+ mRecentsView.onResume(mIsVisible, stack);
+
+ // Animate the SystemUI scrims into view
+ Task launchTarget = stack.getLaunchTarget();
+ int taskCount = stack.getTaskCount();
+ int launchTaskIndexInStack = launchTarget != null
+ ? stack.indexOfStackTask(launchTarget)
+ : 0;
+ boolean hasNavBarScrim = (taskCount > 0) && !config.hasTransposedNavBar;
+ boolean animateNavBarScrim = !launchState.launchedWhileDocking;
+ mScrimViews.prepareEnterRecentsAnimation(hasNavBarScrim, animateNavBarScrim);
+
+ // If this is a new instance from a configuration change, then we have to manually trigger
+ // the enter animation state, or if recents was relaunched by AM, without going through
+ // the normal mechanisms
+ boolean wasLaunchedByAm = !launchState.launchedFromHome &&
+ !launchState.launchedFromApp;
+ if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
+ EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
+ }
+
+ mRecentsView.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+
+ @Override
+ public boolean onPreDraw() {
+ mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
+ EventBus.getDefault().post(new RecentsDrawnEvent());
+ return true;
+ }
+ });
+
+ // Keep track of whether we launched from the nav bar button or via alt-tab
+ if (launchState.launchedWithAltTab) {
+ MetricsLogger.count(this, "overview_trigger_alttab", 1);
+ } else {
+ MetricsLogger.count(this, "overview_trigger_nav_btn", 1);
+ }
+
+ // Keep track of whether we launched from an app or from home
+ 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);
+ } else {
+ MetricsLogger.count(this, "overview_source_home", 1);
+ }
+
+ // Keep track of the total stack task count
+ MetricsLogger.histogram(this, "overview_task_count", taskCount);
+
+ // After we have resumed, set the visible state until the next onStop() call
+ mIsVisible = true;
}
@Override
- protected void onStop() {
- super.onStop();
+ protected void onPause() {
+ super.onPause();
- // Reset some states
mIgnoreAltTabRelease = false;
- if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
- EventBus.getDefault().send(new HideHistoryEvent(false /* animate */));
- }
-
- // Notify that recents is now hidden
- SystemServicesProxy ssp = Recents.getSystemServices();
- EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, false));
+ mIterateTrigger.stopDozing();
// Workaround for b/22542869, if the RecentsActivity is started again, but without going
// through SystemUI, we need to reset the config launch flags to ensure that we do not
@@ -461,7 +438,20 @@
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
launchState.reset();
+ }
+ @Override
+ protected void onStop() {
+ super.onStop();
+
+ // Only hide the history if Recents is completely hidden
+ if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
+ EventBus.getDefault().send(new HideHistoryEvent(false /* animate */));
+ }
+
+ // Notify that recents is now hidden
+ mIsVisible = false;
+ EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
MetricsLogger.hidden(this, MetricsEvent.OVERVIEW_ACTIVITY);
}
@@ -528,16 +518,23 @@
@Override
public void onMultiWindowChanged(boolean inMultiWindow) {
super.onMultiWindowChanged(inMultiWindow);
+ EventBus.getDefault().send(new ConfigurationChangedEvent());
+
+ // Reload the task stack completely
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
RecentsTaskLoader loader = Recents.getTaskLoader();
- RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
- launchOpts.loadIcons = false;
- launchOpts.loadThumbnails = false;
- launchOpts.onlyLoadForCache = true;
RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
- loader.preloadTasks(loadPlan, -1, false);
- loader.loadTasks(this, loadPlan, launchOpts);
- EventBus.getDefault().send(new TaskStackUpdatedEvent(loadPlan.getTaskStack(),
- inMultiWindow));
+ loader.preloadTasks(loadPlan, -1 /* topTaskId */, false /* isTopTaskHome */);
+
+ RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+ loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
+ loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
+ loader.loadTasks(this, loadPlan, loadOpts);
+
+ mRecentsView.onResume(mIsVisible, loadPlan.getTaskStack());
+
+ EventBus.getDefault().send(new MultiWindowStateChangedEvent(inMultiWindow));
}
@Override
@@ -636,7 +633,7 @@
// Focus the next task
EventBus.getDefault().send(new FocusNextTaskViewEvent(timerIndicatorDuration));
- MetricsLogger.action(this, MetricsEvent.OVERVIEW_PAGE);
+ MetricsLogger.action(this, MetricsEvent.ACTION_OVERVIEW_PAGE);
}
}
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 28b2fae..ac23f44 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 {
@@ -568,11 +568,14 @@
// Make sure we inform DividerView before we actually start the activity so we can change
// the resize mode already.
- EventBus.getDefault().send(new DockingTopTaskEvent(dragMode));
- ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds);
- showRecents(false /* triggeredFromAltTab */,
- dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS, false /* animate */,
- true /* reloadTasks*/);
+ if (ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds)) {
+ EventBus.getDefault().send(new DockingTopTaskEvent(dragMode));
+ showRecents(
+ false /* triggeredFromAltTab */,
+ dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS,
+ false /* animate */,
+ true /* launchedWhileDockingTask*/);
+ }
}
/**
@@ -599,7 +602,7 @@
com.android.internal.R.dimen.navigation_bar_width);
mTaskBarHeight = res.getDimensionPixelSize(
R.dimen.recents_task_bar_height);
- mDummyStackView = new TaskStackView(mContext, new TaskStack());
+ mDummyStackView = new TaskStackView(mContext);
mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
null, false);
}
@@ -612,8 +615,7 @@
* is not already bound (can be expensive)
* @param stack the stack to initialize the stack layout with
*/
- private void updateHeaderBarLayout(boolean tryAndBindSearchWidget,
- TaskStack stack) {
+ private void updateHeaderBarLayout(boolean tryAndBindSearchWidget, TaskStack stack) {
RecentsConfiguration config = Recents.getConfiguration();
SystemServicesProxy ssp = Recents.getSystemServices();
Rect systemInsets = new Rect();
@@ -637,14 +639,15 @@
mSearchBarBounds, mTaskStackBounds);
// Rebind the header bar and draw it for the transition
- TaskStackLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
+ TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
Rect taskStackBounds = new Rect(mTaskStackBounds);
- algo.setSystemInsets(systemInsets);
+ stackLayout.setSystemInsets(systemInsets);
if (stack != null) {
- algo.initialize(taskStackBounds,
+ stackLayout.initialize(taskStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
+ mDummyStackView.setTasks(stack, false /* notifyStackChanges */);
}
- Rect taskViewBounds = algo.getUntransformedTaskViewBounds();
+ Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds();
if (!taskViewBounds.equals(mLastTaskViewBounds)) {
mLastTaskViewBounds.set(taskViewBounds);
@@ -702,10 +705,8 @@
updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack);
// 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() {
@@ -751,17 +752,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);
@@ -775,8 +779,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) {
@@ -808,9 +811,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);
@@ -821,7 +825,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;
@@ -849,6 +853,7 @@
c.scale(toTransform.scale, toTransform.scale);
mHeaderBar.rebindToTask(toTask, false /* touchExplorationEnabled */,
disabledInSafeMode);
+ mHeaderBar.setDimAlpha(toTransform.dimAlpha);
mHeaderBar.draw(c);
c.setBitmap(null);
}
@@ -881,7 +886,6 @@
updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack);
// Prepare the dummy stack for the transition
- mDummyStackView.updateLayoutForStack(stack);
TaskStackLayoutAlgorithm.VisibilityReport stackVr =
mDummyStackView.computeStackVisibilityReport();
@@ -897,8 +901,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);
@@ -945,14 +948,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%
copy from core/java/android/hardware/camera2/utils/LongParcelable.aidl
copy 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/events/activity/MultiWindowStateChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
new file mode 100644
index 0000000..19245d9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
@@ -0,0 +1,31 @@
+/*
+ * 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 com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent by the activity whenever the multi-window state has changed.
+ */
+public class MultiWindowStateChangedEvent extends EventBus.Event {
+
+ public final boolean inMultiWindow;
+
+ public MultiWindowStateChangedEvent(boolean inMultiWindow) {
+ this.inMultiWindow = inMultiWindow;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
index 4140bcd..8843eb4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
@@ -19,21 +19,18 @@
import android.content.Context;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.misc.SystemServicesProxy;
/**
- * This is sent when the visibility of the RecentsActivity for the current user changes.
+ * This is sent when the visibility of the RecentsActivity for the current user changes. Handlers
+ * of this event should not alter the UI, as the activity may still be visible.
*/
public class RecentsVisibilityChangedEvent extends EventBus.Event {
public final Context applicationContext;
- public final SystemServicesProxy systemServicesProxy;
public final boolean visible;
- public RecentsVisibilityChangedEvent(Context context, SystemServicesProxy systemServicesProxy,
- boolean visible) {
+ public RecentsVisibilityChangedEvent(Context context, boolean visible) {
this.applicationContext = context.getApplicationContext();
- this.systemServicesProxy = systemServicesProxy;
this.visible = visible;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
index d7b9b9e..5eeda72 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
@@ -161,7 +161,7 @@
ssp.startActivityFromRecents(v.getContext(), task.key.id, task.title,
ActivityOptions.makeBasic());
- MetricsLogger.action(v.getContext(), MetricsEvent.OVERVIEW_SELECT,
+ MetricsLogger.action(v.getContext(), MetricsEvent.ACTION_OVERVIEW_SELECT,
task.key.getComponent().toString());
}
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 4b29c29..532e796 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -338,15 +338,18 @@
}
/** Docks an already resumed task to the side of the screen. */
- public void moveTaskToDockedStack(int taskId, int createMode, Rect initialBounds) {
- if (mIam == null) return;
+ public boolean moveTaskToDockedStack(int taskId, int createMode, Rect initialBounds) {
+ if (mIam == null) {
+ return false;
+ }
try {
- mIam.moveTaskToDockedStack(taskId, createMode, true /* onTop */, false /* animate */,
- initialBounds);
+ return mIam.moveTaskToDockedStack(
+ taskId, createMode, true /* onTop */, false /* animate */, initialBounds);
} catch (RemoteException e) {
e.printStackTrace();
}
+ return false;
}
/** Returns the focused stack id. */
@@ -692,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/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index abcb563..6ae07fc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -212,8 +212,7 @@
// Initialize the stacks
mStack = new TaskStack();
- mStack.setTasks(allTasks, false /* notifyStackChanges */);
- mStack.createAffiliatedGroupings(mContext);
+ mStack.setTasks(mContext, allTasks, false /* notifyStackChanges */);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index e5d4f1b..b5a5949 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -100,11 +100,7 @@
@Override
public String toString() {
- return "Task.Key: " + id + ", "
- + "s: " + stackId + ", "
- + "u: " + userId + ", "
- + "lat: " + lastActiveTime + ", "
- + getComponent().getPackageName();
+ return "t" + id + ", s" + stackId + ", u" + userId;
}
private void updateHashCode() {
@@ -204,7 +200,9 @@
this.isDockable = isDockable;
}
- /** Copies the other task. */
+ /**
+ * Copies the metadata from another task, but retains the current callbacks.
+ */
public void copyFrom(Task o) {
this.key = o.key;
this.group = o.group;
@@ -300,11 +298,6 @@
@Override
public String toString() {
- String groupAffiliation = "no group";
- if (group != null) {
- groupAffiliation = Integer.toString(group.affiliation);
- }
- return "Task (" + groupAffiliation + "): " + key +
- " [" + super.toString() + "]";
+ return "[" + key.toString() + "] " + title;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 1f91dce..4d1c552 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -92,15 +92,6 @@
}
}
- /**
- * Resets the task list, but does not remove the filter.
- */
- void reset() {
- mTasks.clear();
- mFilteredTasks.clear();
- mTaskIndices.clear();
- }
-
/** Removes the task filter and returns the previous touch state */
void removeFilter() {
mFilter = null;
@@ -481,15 +472,6 @@
mCb = cb;
}
- /** Resets this TaskStack. */
- public void reset() {
- mCb = null;
- mStackTaskList.reset();
- mHistoryTaskList.reset();
- mGroups.clear();
- mAffinitiesGroups.clear();
- }
-
/**
* Moves the given task to either the front of the freeform workspace or the stack.
*/
@@ -556,12 +538,12 @@
* @param tasks the new set of tasks to replace the current set.
* @param notifyStackChanges whether or not to callback on specific changes to the list of tasks.
*/
- public void setTasks(List<Task> tasks, boolean notifyStackChanges) {
+ public void setTasks(Context context, List<Task> tasks, boolean notifyStackChanges) {
// Compute a has set for each of the tasks
ArrayMap<Task.TaskKey, Task> currentTasksMap = createTaskKeyMapFromList(mRawTaskList);
ArrayMap<Task.TaskKey, Task> newTasksMap = createTaskKeyMapFromList(tasks);
-
- ArrayList<Task> newTasks = new ArrayList<>();
+ ArrayList<Task> addedTasks = new ArrayList<>();
+ ArrayList<Task> allTasks = new ArrayList<>();
// Disable notifications if there are no callbacks
if (mCb == null) {
@@ -570,10 +552,13 @@
// Remove any tasks that no longer exist
int taskCount = mRawTaskList.size();
- for (int i = 0; i < taskCount; i++) {
+ for (int i = taskCount - 1; i >= 0; i--) {
Task task = mRawTaskList.get(i);
if (!newTasksMap.containsKey(task.key)) {
if (notifyStackChanges) {
+ // If we are notifying, then remove the task now, otherwise the raw task list
+ // will be reset at the end of this method
+ removeTask(task, AnimationProps.IMMEDIATE);
mCb.onStackTaskRemoved(this, task, i == (taskCount - 1), null,
AnimationProps.IMMEDIATE);
}
@@ -584,26 +569,28 @@
// Add any new tasks
taskCount = tasks.size();
for (int i = 0; i < taskCount; i++) {
- Task task = tasks.get(i);
- if (!currentTasksMap.containsKey(task.key)) {
- if (notifyStackChanges) {
- mCb.onStackTaskAdded(this, task);
- }
- newTasks.add(task);
- } else {
- newTasks.add(currentTasksMap.get(task.key));
+ Task newTask = tasks.get(i);
+ Task currentTask = currentTasksMap.get(newTask.key);
+ if (currentTask == null && notifyStackChanges) {
+ addedTasks.add(newTask);
+ } else if (currentTask != null) {
+ // The current task has bound callbacks, so just copy the data from the new task
+ // state and add it back into the list
+ currentTask.copyFrom(newTask);
+ newTask = currentTask;
}
+ allTasks.add(newTask);
}
// Sort all the tasks to ensure they are ordered correctly
- Collections.sort(newTasks, FREEFORM_LAST_ACTIVE_TIME_COMPARATOR);
+ Collections.sort(allTasks, FREEFORM_LAST_ACTIVE_TIME_COMPARATOR);
// Filter out the historical tasks from this new list
ArrayList<Task> stackTasks = new ArrayList<>();
ArrayList<Task> historyTasks = new ArrayList<>();
- int newTaskCount = newTasks.size();
+ int newTaskCount = allTasks.size();
for (int i = 0; i < newTaskCount; i++) {
- Task task = newTasks.get(i);
+ Task task = allTasks.get(i);
if (task.isHistorical) {
historyTasks.add(task);
} else {
@@ -613,10 +600,16 @@
mStackTaskList.set(stackTasks);
mHistoryTaskList.set(historyTasks);
- mRawTaskList.clear();
- mRawTaskList.addAll(newTasks);
- mGroups.clear();
- mAffinitiesGroups.clear();
+ mRawTaskList = allTasks;
+
+ // Only callback for the newly added tasks after this stack has been updated
+ int addedTaskCount = addedTasks.size();
+ for (int i = 0; i < addedTaskCount; i++) {
+ mCb.onStackTaskAdded(this, addedTasks.get(i));
+ }
+
+ // Update the affiliated groupings
+ createAffiliatedGroupings(context);
}
/**
@@ -779,9 +772,12 @@
}
/**
- * Temporary: This method will simulate affiliation groups by
+ * Temporary: This method will simulate affiliation groups
*/
- public void createAffiliatedGroupings(Context context) {
+ void createAffiliatedGroupings(Context context) {
+ mGroups.clear();
+ mAffinitiesGroups.clear();
+
if (RecentsDebugFlags.Static.EnableMockTaskGroups) {
ArrayMap<Task.TaskKey, Task> taskMap = new ArrayMap<>();
// Sort all tasks by increasing firstActiveTime of the task
@@ -926,13 +922,13 @@
@Override
public String toString() {
- String str = "Stack Tasks:\n";
+ String str = "Stack Tasks (" + mStackTaskList.size() + "):\n";
for (Task t : mStackTaskList.getTasks()) {
- str += " " + t.toString() + "\n";
+ str += " " + t.toString() + "\n";
}
- str += "Historical Tasks:\n";
+ str += "Historical Tasks(" + mHistoryTaskList.size() + "):\n";
for (Task t : mHistoryTaskList.getTasks()) {
- str += " " + t.toString() + "\n";
+ str += " " + t.toString() + "\n";
}
return str;
}
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..dae522f 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,14 +287,14 @@
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());
}
// Notify that recents is now visible
SystemServicesProxy ssp = Recents.getSystemServices();
- EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
+ EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true));
if (mPipManager.isPipShown()) {
// Place mPipView at the PIP bounds for fine tuned focus handling.
@@ -340,8 +343,7 @@
mPipManager.removeListener(mPipListener);
mIgnoreAltTabRelease = false;
// Notify that recents is now hidden
- SystemServicesProxy ssp = Recents.getSystemServices();
- EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, false));
+ EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
// Workaround for b/22542869, if the RecentsActivity is started again, but without going
// through SystemUI, we need to reset the config launch flags to ensure that we do not
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..dd825cb 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));
}
/**
@@ -176,6 +177,7 @@
// Keep track of failed launches
EventBus.getDefault().send(new LaunchTaskFailedEvent());
}
+
if (transitionFuture != null) {
IRemoteCallback.Stub callback = null;
if (animStartedListener != null) {
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..1af5a55 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -60,9 +60,7 @@
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.activity.ShowHistoryButtonEvent;
import com.android.systemui.recents.events.activity.ShowHistoryEvent;
-import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
import com.android.systemui.recents.events.activity.ToggleHistoryEvent;
-import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
import com.android.systemui.recents.events.ui.ResetBackgroundScrimEvent;
@@ -168,35 +166,39 @@
}
/** Set/get the bsp root node */
- public void setTaskStack(TaskStack stack) {
+ public void onResume(boolean isResumingFromVisible, TaskStack stack) {
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
- mStack = stack;
- if (launchState.launchedReuseTaskStackViews) {
- if (mTaskStackView != null) {
- // If onRecentsHidden is not triggered, we need to the stack view again here
- mTaskStackView.reset();
- mTaskStackView.setStack(stack);
- } else {
- mTaskStackView = new TaskStackView(getContext(), stack);
- addView(mTaskStackView);
- }
- } else {
- if (mTaskStackView != null) {
- removeView(mTaskStackView);
- }
- mTaskStackView = new TaskStackView(getContext(), stack);
+
+ if (mTaskStackView == null || !launchState.launchedReuseTaskStackViews) {
+ isResumingFromVisible = false;
+ removeView(mTaskStackView);
+ mTaskStackView = new TaskStackView(getContext());
+ mStack = mTaskStackView.getStack();
addView(mTaskStackView);
}
- // 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
- || mStack.getTaskCount() == 0) {
- mBackgroundScrim.setAlpha((int) (DEFAULT_SCRIM_ALPHA * 255));
+ // Reset the state
+ mAwaitingFirstLayout = !isResumingFromVisible;
+ mLastTaskLaunchedWasFreeform = false;
+
+ // Update the stack
+ mTaskStackView.onResume(isResumingFromVisible);
+ mTaskStackView.setTasks(stack, isResumingFromVisible /* notifyStackChanges */);
+
+ if (isResumingFromVisible) {
+ // If we are already visible, then restore the background scrim
+ animateBackgroundScrim(DEFAULT_SCRIM_ALPHA, DEFAULT_UPDATE_SCRIM_DURATION);
} else {
- mBackgroundScrim.setAlpha(0);
+ // If we are already occluded by the app, then set the final background scrim alpha now.
+ // Otherwise, defer until the enter animation completes to animate the scrim alpha with
+ // the tasks for the home animation.
+ if (launchState.launchedWhileDocking || launchState.launchedFromApp
+ || mStack.getTaskCount() == 0) {
+ mBackgroundScrim.setAlpha((int) (DEFAULT_SCRIM_ALPHA * 255));
+ } else {
+ mBackgroundScrim.setAlpha(0);
+ }
}
// Update the top level view's visibilities
@@ -205,9 +207,6 @@
} else {
showEmptyView();
}
-
- // Trigger a new layout
- requestLayout();
}
/**
@@ -662,16 +661,9 @@
animator.start();
}
- public final void onBusEvent(TaskStackUpdatedEvent event) {
- if (!event.inMultiWindow) {
- mStack.setTasks(event.stack.computeAllTasksList(), true /* notifyStackChanges */);
- mStack.createAffiliatedGroupings(getContext());
- }
- }
-
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);
@@ -686,17 +678,6 @@
animateBackgroundScrim(DEFAULT_SCRIM_ALPHA, DEFAULT_UPDATE_SCRIM_DURATION);
}
- public final void onBusEvent(RecentsVisibilityChangedEvent event) {
- if (!event.visible) {
- // Reset the view state
- mAwaitingFirstLayout = true;
- mLastTaskLaunchedWasFreeform = false;
- if (RecentsDebugFlags.Static.EnableHistory) {
- hideHistoryButton(0, false /* translate */);
- }
- }
- }
-
public final void onBusEvent(ToggleHistoryEvent event) {
if (!RecentsDebugFlags.Static.EnableHistory) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 1cd0850..19b219a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -16,9 +16,11 @@
package com.android.systemui.recents.views;
+import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
import android.content.Context;
import android.view.View;
+import android.view.ViewPropertyAnimator;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -56,25 +58,41 @@
View.VISIBLE : View.INVISIBLE);
}
+ /**
+ * Animates the nav bar scrim visibility.
+ */
+ public void animateNavBarScrimVisibility(boolean visible, AnimationProps animation) {
+ int toY = 0;
+ if (visible) {
+ mNavBarScrimView.setVisibility(View.VISIBLE);
+ mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
+ } else {
+ toY = mNavBarScrimView.getMeasuredHeight();
+ }
+ if (animation != AnimationProps.IMMEDIATE) {
+ mNavBarScrimView.animate()
+ .translationY(toY)
+ .setDuration(animation.getDuration(AnimationProps.BOUNDS))
+ .setInterpolator(animation.getInterpolator(AnimationProps.BOUNDS))
+ .start();
+ } else {
+ mNavBarScrimView.setTranslationY(toY);
+ }
+ }
+
/**** EventBus events ****/
/**
* Starts animating the scrim views when entering Recents.
*/
public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
- if (mHasNavBarScrim && mShouldAnimateNavBarScrim) {
- mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
- mNavBarScrimView.animate()
- .translationY(0)
- .setDuration(mNavBarScrimEnterDuration)
- .setInterpolator(Interpolators.DECELERATE_QUINT)
- .withStartAction(new Runnable() {
- @Override
- public void run() {
- mNavBarScrimView.setVisibility(View.VISIBLE);
- }
- })
- .start();
+ if (mHasNavBarScrim) {
+ AnimationProps animation = mShouldAnimateNavBarScrim
+ ? new AnimationProps()
+ .setDuration(AnimationProps.BOUNDS, mNavBarScrimEnterDuration)
+ .setInterpolator(AnimationProps.BOUNDS, Interpolators.DECELERATE_QUINT)
+ : AnimationProps.IMMEDIATE;
+ animateNavBarScrimVisibility(true, animation);
}
}
@@ -83,13 +101,12 @@
* going home).
*/
public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
- if (mHasNavBarScrim && mShouldAnimateNavBarScrim) {
- mNavBarScrimView.animate()
- .translationY(mNavBarScrimView.getMeasuredHeight())
- .setStartDelay(0)
- .setDuration(TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .start();
+ if (mHasNavBarScrim) {
+ AnimationProps animation = new AnimationProps()
+ .setDuration(AnimationProps.BOUNDS,
+ TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION)
+ .setInterpolator(AnimationProps.BOUNDS, Interpolators.FAST_OUT_SLOW_IN);
+ animateNavBarScrimVisibility(false, animation);
}
}
}
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..758f4d82 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..a5ed32a 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,86 @@
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;
+ }
+
+ 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,10 +562,18 @@
}
}
+ public void clearUnfocusedTaskOverrides() {
+ mTaskIndexOverrideMap.clear();
+ }
+
/**
* Updates this stack when a scroll happens.
*/
public void updateFocusStateOnScroll(float stackScroll, float deltaScroll) {
+ if (deltaScroll == 0f) {
+ return;
+ }
+
for (int i = mTaskIndexOverrideMap.size() - 1; i >= 0; i--) {
int taskId = mTaskIndexOverrideMap.keyAt(i);
float x = mTaskIndexMap.get(taskId);
@@ -523,7 +593,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 +602,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;
+ }
}
/**
@@ -559,6 +634,13 @@
}
/**
+ * Returns whether this stack layout has been initialized.
+ */
+ public boolean isInitialized() {
+ return !mStackRect.isEmpty();
+ }
+
+ /**
* Computes the maximum number of visible tasks and thumbnails when the scroll is at the initial
* stack scroll. Requires that update() is called first.
*/
@@ -577,7 +659,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 +682,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 +718,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 +770,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 +781,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 +826,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),
@@ -820,11 +916,11 @@
float peekHeightPct = (float) mFocusedTopPeekHeight / mStackRect.height();
float slope = ((1f - peekHeightPct) - cpoint1Y) / (0.5f - cpoint1X);
float b = 1f - slope * cpoint1X;
- float cpoint2X = 0.75f;
+ float cpoint2X = 0.65f;
float cpoint2Y = slope * cpoint2X + b;
Path p = new Path();
p.moveTo(0f, 1f);
- p.cubicTo(0f, 1f, cpoint1X, 1f, 0.5f, 1f - peekHeightPct);
+ p.cubicTo(0f, 1f, cpoint1X, cpoint1Y, 0.5f, 1f - peekHeightPct);
p.cubicTo(0.5f, 1f - peekHeightPct, cpoint2X, cpoint2Y, 1f, 0f);
return p;
}
@@ -851,8 +947,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 +966,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..9da8fee 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;
@@ -65,15 +65,13 @@
import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.activity.LaunchTaskStartedEvent;
+import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
import com.android.systemui.recents.events.activity.PackagesChangedEvent;
import com.android.systemui.recents.events.activity.ShowHistoryButtonEvent;
import com.android.systemui.recents.events.activity.ShowHistoryEvent;
-import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
-import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
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;
@@ -118,7 +116,7 @@
private static final ArraySet<Task.TaskKey> EMPTY_TASK_SET = new ArraySet<>();
LayoutInflater mInflater;
- TaskStack mStack;
+ TaskStack mStack = new TaskStack();
@ViewDebug.ExportedProperty(deepExport=true, prefix="layout_")
TaskStackLayoutAlgorithm mLayoutAlgorithm;
@ViewDebug.ExportedProperty(deepExport=true, prefix="scroller_")
@@ -207,13 +205,13 @@
}
};
- public TaskStackView(Context context, TaskStack stack) {
+ public TaskStackView(Context context) {
super(context);
SystemServicesProxy ssp = Recents.getSystemServices();
Resources res = context.getResources();
// Set the stack first
- setStack(stack);
+ mStack.setCallbacks(this);
mViewPool = new ViewPool<>(context, this);
mInflater = LayoutInflater.from(context);
mLayoutAlgorithm = new TaskStackLayoutAlgorithm(context, this);
@@ -249,6 +247,41 @@
}
}
+ /**
+ * Called only if we are resuming Recents.
+ */
+ void onResume(boolean isResumingFromVisible) {
+ if (!isResumingFromVisible) {
+ // Reset the focused task
+ resetFocusedTask(getFocusedTask());
+ }
+
+ // Reset the state of each of the task views
+ List<TaskView> taskViews = new ArrayList<>();
+ taskViews.addAll(getTaskViews());
+ taskViews.addAll(mViewPool.getViews());
+ for (int i = taskViews.size() - 1; i >= 0; i--) {
+ taskViews.get(i).onResume(isResumingFromVisible);
+ }
+
+ // Reset the stack state
+ readSystemFlags();
+ mTaskViewsClipDirty = true;
+ mEnterAnimationComplete = false;
+ mUIDozeTrigger.stopDozing();
+ if (isResumingFromVisible) {
+ // Animate in the freeform workspace
+ int ffBgAlpha = mLayoutAlgorithm.getStackState().freeformBackgroundAlpha;
+ animateFreeformWorkspaceBackgroundAlpha(ffBgAlpha, new AnimationProps(150,
+ Interpolators.FAST_OUT_SLOW_IN));
+ } else {
+ mStackScroller.reset();
+ mLayoutAlgorithm.reset();
+ mAwaitingFirstLayout = true;
+ requestLayout();
+ }
+ }
+
@Override
protected void onAttachedToWindow() {
EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
@@ -262,22 +295,44 @@
EventBus.getDefault().unregister(this);
}
- /** Sets the task stack */
- void setStack(TaskStack stack) {
- // Set the new stack
- mStack = stack;
- if (mStack != null) {
- mStack.setCallbacks(this);
+ /**
+ * Sets the stack tasks of this TaskStackView from the given TaskStack.
+ */
+ public void setTasks(TaskStack stack, boolean notifyStackChanges) {
+ boolean isInitialized = mLayoutAlgorithm.isInitialized();
+ mStack.setTasks(getContext(), stack.computeAllTasksList(),
+ notifyStackChanges && isInitialized);
+ if (isInitialized) {
+ // Only update the layout if we are notifying, otherwise, we will update it in the next
+ // measure/layout pass
+ updateLayoutAlgorithm(false /* boundScroll */, EMPTY_TASK_SET);
+ updateToInitialState();
+ relayoutTaskViews(AnimationProps.IMMEDIATE);
+
+ // Rebind all the task views. This will not trigger new resources to be loaded unless
+ // they have actually changed
+ List<TaskView> taskViews = getTaskViews();
+ int taskViewCount = taskViews.size();
+ for (int i = 0; i < taskViewCount; i++) {
+ TaskView tv = taskViews.get(i);
+ bindTaskView(tv, tv.getTask());
+ }
}
- // Layout again with the new stack
- requestLayout();
}
/** 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();
@@ -331,37 +386,6 @@
return null;
}
- /** Resets this TaskStackView for reuse. */
- void reset() {
- // Reset the focused task
- resetFocusedTask(getFocusedTask());
-
- // Return all the views to the pool
- List<TaskView> taskViews = getTaskViews();
- int taskViewCount = taskViews.size();
- for (int i = taskViewCount - 1; i >= 0; i--) {
- mViewPool.returnViewToPool(taskViews.get(i));
- }
-
- // Mark each task view for relayout
- List<TaskView> poolViews = mViewPool.getViews();
- for (TaskView tv : poolViews) {
- tv.reset();
- }
-
- // Reset the stack state
- mStack.reset();
- mTaskViewsClipDirty = true;
- mAwaitingFirstLayout = true;
- mEnterAnimationComplete = false;
- mUIDozeTrigger.stopDozing();
- mUIDozeTrigger.resetTrigger();
- mStackScroller.reset();
- mLayoutAlgorithm.reset();
- readSystemFlags();
- requestLayout();
- }
-
/** Returns the stack algorithm for this task stack. */
public TaskStackLayoutAlgorithm getStackAlgorithm() {
return mLayoutAlgorithm;
@@ -410,7 +434,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 +454,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 +492,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 +513,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();
@@ -502,15 +532,22 @@
for (int i = taskViewCount - 1; i >= 0; i--) {
TaskView tv = taskViews.get(i);
Task task = tv.getTask();
- int taskIndex = mStack.indexOfStackTask(task);
- TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex);
// Skip ignored tasks
if (ignoreTasksSet.contains(task.key)) {
continue;
}
- if (task.isFreeformTask() || transform.visible) {
+ // It is possible for the set of lingering TaskViews to differ from the stack if the
+ // stack was updated before the relayout. If the task view is no longer in the stack,
+ // then just return it back to the view pool.
+ int taskIndex = mStack.indexOfStackTask(task);
+ TaskViewTransform transform = null;
+ if (taskIndex != -1) {
+ transform = mCurrentTaskTransforms.get(taskIndex);
+ }
+
+ if (task.isFreeformTask() || (transform != null && transform.visible)) {
mTmpTaskViewMap.put(task.key, tv);
} else {
if (mTouchExplorationEnabled) {
@@ -605,15 +642,16 @@
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();
int taskViewCount = taskViews.size();
for (int i = 0; i < taskViewCount; i++) {
- final TaskView tv = taskViews.get(i);
- final int taskIndex = mStack.indexOfStackTask(tv.getTask());
- final TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex);
+ TaskView tv = taskViews.get(i);
+ int taskIndex = mStack.indexOfStackTask(tv.getTask());
+ TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex);
if (ignoreTasksSet.contains(tv.getTask().key)) {
continue;
@@ -657,7 +695,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 +713,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 +798,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 +897,7 @@
cancelAllTaskViewAnimations();
}
+ mLayoutAlgorithm.clearUnfocusedTaskOverrides();
willScroll = mAnimationHelper.startScrollToFocusedTaskAnimation(newFocusedTask,
requestViewFocus);
} else {
@@ -1107,15 +1145,6 @@
}
/**
- * This is ONLY used from the Recents component to update the dummy stack view for purposes
- * of getting the task rect to animate to.
- */
- public void updateLayoutForStack(TaskStack stack) {
- mStack = stack;
- updateLayoutAlgorithm(false /* boundScroll */, EMPTY_TASK_SET);
- }
-
- /**
* Computes the maximum number of visible tasks and thumbnails. Requires that
* updateLayoutForStack() is called first.
*/
@@ -1162,11 +1191,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();
@@ -1405,8 +1439,8 @@
public void onReturnViewToPool(TaskView tv) {
final Task task = tv.getTask();
- // Report that this tasks's data is no longer being used
- Recents.getTaskLoader().unloadTaskData(task);
+ // Unbind the task from the task view
+ unbindTaskView(tv, task);
// Reset the view properties and view state
tv.resetViewProperties();
@@ -1451,14 +1485,11 @@
// Update the task views list after adding the new task view
updateTaskViewsList();
- // Rebind the task and request that this task's data be filled into the TaskView
- tv.onTaskBound(task);
-
- // Load the task data
- Recents.getTaskLoader().loadTaskData(task, true /* fetchAndInvalidateThumbnails */);
+ // Bind the task view to the new task
+ bindTaskView(tv, task);
// If the doze trigger has already fired, then update the state for this task view
- if (mUIDozeTrigger.hasTriggered()) {
+ if (mUIDozeTrigger.isAsleep()) {
tv.setNoUserInteractionState();
}
@@ -1487,6 +1518,19 @@
return (tv.getTask() == preferredData);
}
+ private void bindTaskView(TaskView tv, Task task) {
+ // Rebind the task and request that this task's data be filled into the TaskView
+ tv.onTaskBound(task);
+
+ // Load the task data
+ Recents.getTaskLoader().loadTaskData(task, true /* fetchAndInvalidateThumbnails */);
+ }
+
+ private void unbindTaskView(TaskView tv, Task task) {
+ // Report that this task's data is no longer being used
+ Recents.getTaskLoader().unloadTaskData(task);
+ }
+
/**** TaskViewCallbacks Implementation ****/
@Override
@@ -1652,12 +1696,6 @@
}
}
- public final void onBusEvent(RecentsVisibilityChangedEvent event) {
- if (!event.visible) {
- reset();
- }
- }
-
public final void onBusEvent(DragStartEvent event) {
// Ensure that the drag task is not animated
addIgnoreTask(event.task);
@@ -1754,12 +1792,14 @@
event.taskView.setLeftTopRightBottom(taskViewRect.left, taskViewRect.top,
taskViewRect.right, taskViewRect.bottom);
- // Animate all the TaskViews back into position
+ // Animate the non-drag TaskViews back into position
mLayoutAlgorithm.getStackTransform(event.task, getScroller().getStackScroll(),
mTmpTransform, null);
event.getAnimationTrigger().increment();
relayoutTaskViews(new AnimationProps(DEFAULT_SYNC_STACK_DURATION,
Interpolators.FAST_OUT_SLOW_IN));
+
+ // Animate the drag TaskView back into position
updateTaskViewToTransform(event.taskView, mTmpTransform,
new AnimationProps(DEFAULT_SYNC_STACK_DURATION, Interpolators.FAST_OUT_SLOW_IN,
event.getAnimationTrigger().decrementOnAnimationEnd()));
@@ -1832,31 +1872,28 @@
mAnimationHelper.startHideHistoryAnimation();
}
- public final void onBusEvent(TaskStackUpdatedEvent event) {
+ public final void onBusEvent(MultiWindowStateChangedEvent event) {
if (!event.inMultiWindow) {
- // Scroll the stack to the front after it has been updated
- event.addPostAnimationCallback(new Runnable() {
+ // Scroll the stack to the front to see the undocked task
+ mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP, new Runnable() {
@Override
public void run() {
- mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP,
- null /* postScrollRunnable */);
+ List<TaskView> taskViews = getTaskViews();
+ int taskViewCount = taskViews.size();
+ for (int i = 0; i < taskViewCount; i++) {
+ TaskView tv = taskViews.get(i);
+ tv.getHeaderView().rebindToTask(tv.getTask(), tv.mTouchExplorationEnabled,
+ tv.mIsDisabledInSafeMode);
+ }
}
});
}
- // When the multi-window state changes, rebind all task view headers again to update their
- // dockable state
- event.addPostAnimationCallback(new Runnable() {
- @Override
- public void run() {
- List<TaskView> taskViews = getTaskViews();
- int taskViewCount = taskViews.size();
- for (int i = 0; i < taskViewCount; i++) {
- TaskView tv = taskViews.get(i);
- tv.getHeaderView().rebindToTask(tv.getTask(), tv.mTouchExplorationEnabled,
- tv.mIsDisabledInSafeMode);
- }
- }
- });
+ }
+
+ public final void onBusEvent(ConfigurationChangedEvent event) {
+ mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
+ mLayoutAlgorithm.initialize(mStackBounds,
+ TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
}
/**
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..8635911 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -20,6 +20,7 @@
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Path;
import android.graphics.Rect;
import android.util.ArrayMap;
import android.util.MutableBoolean;
@@ -44,6 +45,7 @@
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
+import com.android.systemui.recents.misc.FreePathInterpolator;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
@@ -60,6 +62,16 @@
private static final int INACTIVE_POINTER_ID = -1;
private static final Interpolator STACK_TRANSFORM_INTERPOLATOR =
new PathInterpolator(0.73f, 0.33f, 0.42f, 0.85f);
+ // The min overscroll is the amount of task progress overscroll we want / the max overscroll
+ // curve value below
+ private static final float MAX_OVERSCROLL = 0.7f / 0.3f;
+ private static final Interpolator OVERSCROLL_INTERP;
+ static {
+ Path OVERSCROLL_PATH = new Path();
+ OVERSCROLL_PATH.moveTo(0, 0);
+ OVERSCROLL_PATH.cubicTo(0.2f, 0.175f, 0.25f, 0.3f, 1f, 0.3f);
+ OVERSCROLL_INTERP = new FreePathInterpolator(OVERSCROLL_PATH);
+ }
Context mContext;
TaskStackView mSv;
@@ -245,6 +257,18 @@
// of the curve, so just move the scroll proportional to that
float deltaP = layoutAlgorithm.getDeltaPForY(mDownY, y);
float curScrollP = mDownScrollP + deltaP;
+
+ // Modulate the overscroll to prevent users from pulling the stack too far
+ float minScrollP = layoutAlgorithm.mMinScrollP;
+ float maxScrollP = layoutAlgorithm.mMaxScrollP;
+ if (curScrollP < minScrollP || curScrollP > maxScrollP) {
+ float clampedScrollP = Utilities.clamp(curScrollP, minScrollP, maxScrollP);
+ float overscrollP = (curScrollP - clampedScrollP);
+ float overscrollX = Math.abs(overscrollP) / MAX_OVERSCROLL;
+ curScrollP = clampedScrollP + (Math.signum(overscrollP) *
+ (OVERSCROLL_INTERP.getInterpolation(overscrollX) * MAX_OVERSCROLL));
+ }
+
mScroller.setStackScroll(curScrollP);
mStackViewScrolledEvent.updateY(y - mLastY);
EventBus.getDefault().send(mStackViewScrolledEvent);
@@ -446,7 +470,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 +510,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 0c78e6a..0bc7f89 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 =
@@ -175,11 +193,13 @@
}
/** Resets this TaskView for reuse. */
- void reset() {
- resetViewProperties();
+ void onResume(boolean isResumingFromVisible) {
resetNoUserInteractionState();
readSystemFlags();
- setClipViewInStack(false);
+ if (!isResumingFromVisible) {
+ resetViewProperties();
+ setClipViewInStack(false);
+ }
setCallbacks(null);
}
@@ -388,21 +408,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 +429,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 +514,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 +539,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,
@@ -603,7 +604,7 @@
EventBus.getDefault().send(new LaunchTaskEvent(this, mTask, null, INVALID_STACK_ID,
screenPinningRequested));
- MetricsLogger.action(v.getContext(), MetricsEvent.OVERVIEW_SELECT,
+ MetricsLogger.action(v.getContext(), MetricsEvent.ACTION_OVERVIEW_SELECT,
mTask.key.getComponent().toString());
}
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/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index effe581..5652c7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -36,7 +36,9 @@
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.notification.FakeShadowView;
+import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
* Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
@@ -121,6 +123,7 @@
private float mAnimationTranslationY;
private boolean mDrawingAppearAnimation;
private ValueAnimator mAppearAnimator;
+ private ValueAnimator mBackgroundColorAnimator;
private float mAppearAnimationFraction = -1.0f;
private float mAppearAnimationTranslation;
private boolean mShowingLegacyBackground;
@@ -157,6 +160,9 @@
};
private float mShadowAlpha = 1.0f;
private FakeShadowView mFakeShadow;
+ private int mCurrentBackgroundTint;
+ private int mTargetTint;
+ private int mStartTint;
public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -457,21 +463,63 @@
* Sets the tint color of the background
*/
public void setTintColor(int color) {
+ setTintColor(color, false);
+ }
+
+ /**
+ * Sets the tint color of the background
+ */
+ public void setTintColor(int color, boolean animated) {
mBgTint = color;
- updateBackgroundTint();
+ updateBackgroundTint(animated);
}
protected void updateBackgroundTint() {
- int color = getBgColor();
+ updateBackgroundTint(false /* animated */);
+ }
+
+ private void updateBackgroundTint(boolean animated) {
+ if (mBackgroundColorAnimator != null) {
+ mBackgroundColorAnimator.cancel();
+ }
int rippleColor = getRippleColor();
+ mBackgroundDimmed.setRippleColor(rippleColor);
+ mBackgroundNormal.setRippleColor(rippleColor);
+ int color = calculateBgColor();
+ if (!animated) {
+ setBackgroundTintColor(color);
+ } else if (color != mCurrentBackgroundTint) {
+ mStartTint = mCurrentBackgroundTint;
+ mTargetTint = color;
+ mBackgroundColorAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
+ mBackgroundColorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ int newColor = NotificationUtils.interpolateColors(mStartTint, mTargetTint,
+ animation.getAnimatedFraction());
+ setBackgroundTintColor(newColor);
+ }
+ });
+ mBackgroundColorAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ mBackgroundColorAnimator.setInterpolator(Interpolators.LINEAR);
+ mBackgroundColorAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBackgroundColorAnimator = null;
+ }
+ });
+ mBackgroundColorAnimator.start();
+ }
+ }
+
+ private void setBackgroundTintColor(int color) {
+ mCurrentBackgroundTint = color;
if (color == mNormalColor) {
// We don't need to tint a normal notification
color = 0;
}
mBackgroundDimmed.setTint(color);
mBackgroundNormal.setTint(color);
- mBackgroundDimmed.setRippleColor(rippleColor);
- mBackgroundNormal.setRippleColor(rippleColor);
}
/**
@@ -773,8 +821,12 @@
protected abstract View getContentView();
- public int getBgColor() {
- if (mBgTint != 0) {
+ public int calculateBgColor() {
+ return calculateBgColor(true /* withTint */);
+ }
+
+ private int calculateBgColor(boolean withTint) {
+ if (withTint && mBgTint != 0) {
return mBgTint;
} else if (mShowingLegacyBackground) {
return mLegacyColor;
@@ -839,7 +891,7 @@
}
public boolean hasSameBgColor(ActivatableNotificationView otherView) {
- return getBgColor() == otherView.getBgColor();
+ return calculateBgColor() == otherView.calculateBgColor();
}
@Override
@@ -863,6 +915,10 @@
outlineTranslation);
}
+ public int getBackgroundColorWithoutTint() {
+ return calculateBgColor(false /* withTint */);
+ }
+
public interface OnActivatedListener {
void onActivated(ActivatableNotificationView view);
void onActivationReset(ActivatableNotificationView view);
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..c2e1f7d 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;
@@ -412,8 +411,7 @@
}
public ExpandableNotificationRow getViewAtPosition(float y) {
- if (!mIsSummaryWithChildren || !mChildrenExpanded
- || (getNotificationChildren().size() == 1 && isClearable())) {
+ if (!mIsSummaryWithChildren || !mChildrenExpanded) {
return this;
} else {
ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
@@ -570,6 +568,13 @@
mPublicLayout.reInflateViews();
}
+ public void setContentBackground(int customBackgroundColor, boolean animate,
+ NotificationContentView notificationContentView) {
+ if (getShowingLayout() == notificationContentView) {
+ setTintColor(customBackgroundColor, animate);
+ }
+ }
+
public interface ExpansionLogger {
public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
@@ -615,20 +620,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 +685,7 @@
mTranslateableViews.remove(mGutsStub);
}
- public void setTranslationForOutline(float translationX) {
+ private void setTranslationForOutline(float translationX) {
setOutlineRect(false, translationX, getTop(), getRight() + translationX, getBottom());
}
@@ -704,6 +705,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 +756,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 +778,7 @@
set.play(translateAnim);
}
}
- mTranslateAnim = set;
- set.start();
+ return set;
}
public float getSpaceForGear() {
@@ -748,10 +795,6 @@
return mSettingsIconRow;
}
- public ArrayList<View> getContentViews() {
- return mTranslateableViews;
- }
-
public void inflateGuts() {
if (mGuts == null) {
mGutsStub.inflate();
@@ -922,18 +965,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()) {
@@ -986,7 +1017,6 @@
}
mPrivateLayout.updateExpandButtons(isExpandable());
updateChildrenHeaderAppearance();
- updateHeaderChildCount();
updateChildrenVisibility();
}
@@ -999,7 +1029,11 @@
* @return whether the view state is currently expanded.
*/
public boolean isExpanded() {
- return !mOnKeyguard
+ return isExpanded(false /* allowOnKeyguard */);
+ }
+
+ public boolean isExpanded(boolean allowOnKeyguard) {
+ return (!mOnKeyguard || allowOnKeyguard)
&& (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
|| isUserExpanded());
}
@@ -1015,12 +1049,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() {
@@ -1084,7 +1113,8 @@
} else {
animateShowingPublic(delay, duration);
}
-
+ NotificationContentView showingLayout = getShowingLayout();
+ showingLayout.updateBackgroundColor(animated);
mPrivateLayout.updateExpandButtons(isExpandable());
updateClearability();
mShowingPublicInitialized = true;
@@ -1142,13 +1172,6 @@
}
}
- public void updateHeaderChildCount() {
- if (mIsSummaryWithChildren) {
- mNotificationHeader.setChildCount(
- mChildrenContainer.getNotificationChildren().size());
- }
- }
-
public static void applyTint(View v, int color) {
int alpha;
if (color != 0) {
@@ -1169,6 +1192,10 @@
return mMaxExpandHeight;
}
+ public boolean areGutsExposed() {
+ return (mGuts != null && mGuts.areGutsExposed());
+ }
+
@Override
public boolean isContentExpandable() {
NotificationContentView showingLayout = getShowingLayout();
@@ -1256,15 +1283,7 @@
header.reapply(getContext(), mNotificationHeader);
mNotificationHeaderWrapper.notifyContentUpdated(mEntry.notification);
}
- updateHeaderExpandButton();
updateChildrenHeaderAppearance();
- updateHeaderChildCount();
- }
-
- private void updateHeaderExpandButton() {
- if (mIsSummaryWithChildren) {
- mNotificationHeader.setIsGroupHeader(true /* isGroupHeader*/);
- }
}
public void updateChildrenHeaderAppearance() {
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..3b87577 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -33,6 +33,7 @@
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
import com.android.systemui.statusbar.notification.NotificationCustomViewWrapper;
+import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.NotificationViewWrapper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.RemoteInputView;
@@ -48,7 +49,7 @@
private static final int VISIBLE_TYPE_EXPANDED = 1;
private static final int VISIBLE_TYPE_HEADSUP = 2;
private static final int VISIBLE_TYPE_SINGLELINE = 3;
- private static final int UNDEFINED = -1;
+ public static final int UNDEFINED = -1;
private final Rect mClipBounds = new Rect();
private final int mMinContractedHeight;
@@ -92,7 +93,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 +121,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 +256,7 @@
updateVisibility();
}
- public void reset(boolean resetActualHeight) {
+ public void reset() {
if (mContractedChild != null) {
mContractedChild.animate().cancel();
removeView(mContractedChild);
@@ -264,10 +272,6 @@
mContractedChild = null;
mExpandedChild = null;
mHeadsUpChild = null;
- mVisibleType = VISIBLE_TYPE_CONTRACTED;
- if (resetActualHeight) {
- mContentHeight = mSmallHeight;
- }
}
public View getContractedChild() {
@@ -364,6 +368,7 @@
getViewForVisibleType(visibleType).setVisibility(View.VISIBLE);
hiddenView.transformTo(shownView, 0.0f);
mVisibleType = visibleType;
+ updateBackgroundColor(true /* animate */);
}
if (mTransformationStartVisibleType != UNDEFINED
&& mVisibleType != mTransformationStartVisibleType) {
@@ -373,11 +378,29 @@
float transformationAmount = calculateTransformationAmount();
shownView.transformFrom(hiddenView, transformationAmount);
hiddenView.transformTo(shownView, transformationAmount);
+ updateBackgroundTransformation(transformationAmount);
} else {
updateViewVisibilities(visibleType);
+ updateBackgroundColor(false);
}
}
+ private void updateBackgroundTransformation(float transformationAmount) {
+ int endColor = getBackgroundColor(mVisibleType);
+ int startColor = getBackgroundColor(mTransformationStartVisibleType);
+ if (endColor != startColor) {
+ if (startColor == 0) {
+ startColor = mContainingNotification.getBackgroundColorWithoutTint();
+ }
+ if (endColor == 0) {
+ endColor = mContainingNotification.getBackgroundColorWithoutTint();
+ }
+ endColor = NotificationUtils.interpolateColors(startColor, endColor,
+ transformationAmount);
+ }
+ mContainingNotification.setContentBackground(endColor, false, this);
+ }
+
private float calculateTransformationAmount() {
int startHeight = getViewForVisibleType(mTransformationStartVisibleType).getHeight();
int endHeight = getViewForVisibleType(mVisibleType).getHeight();
@@ -454,9 +477,24 @@
updateViewVisibilities(visibleType);
}
mVisibleType = visibleType;
+ updateBackgroundColor(animate);
}
}
+ public void updateBackgroundColor(boolean animate) {
+ int customBackgroundColor = getBackgroundColor(mVisibleType);
+ mContainingNotification.setContentBackground(customBackgroundColor, animate, this);
+ }
+
+ private int getBackgroundColor(int visibleType) {
+ NotificationViewWrapper currentVisibleWrapper = getVisibleWrapper(visibleType);
+ int customBackgroundColor = 0;
+ if (currentVisibleWrapper != null) {
+ customBackgroundColor = currentVisibleWrapper.getCustomBackgroundColor();
+ }
+ return customBackgroundColor;
+ }
+
private void updateViewVisibilities(int visibleType) {
boolean contractedVisible = visibleType == VISIBLE_TYPE_CONTRACTED;
mContractedWrapper.setVisible(contractedVisible);
@@ -477,12 +515,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);
+ }
}
});
}
@@ -521,8 +565,8 @@
}
}
- private NotificationViewWrapper getCurrentVisibleWrapper() {
- switch (mVisibleType) {
+ private NotificationViewWrapper getVisibleWrapper(int visibleType) {
+ switch (visibleType) {
case VISIBLE_TYPE_EXPANDED:
return mExpandedWrapper;
case VISIBLE_TYPE_HEADSUP:
@@ -540,9 +584,12 @@
private int calculateVisibleType() {
if (mUserExpanding) {
int height = !mIsChildInGroup || isGroupExpanded()
- || mContainingNotification.isExpanded()
+ || mContainingNotification.isExpanded(true /* allowOnKeyguard */)
? mContainingNotification.getMaxContentHeight()
: mContainingNotification.getShowingLayout().getMinHeight();
+ if (height == 0) {
+ height = mContentHeight;
+ }
int expandedVisualType = getVisualTypeForHeight(height);
int collapsedVisualType = getVisualTypeForHeight(
mContainingNotification.getMinExpandHeight());
@@ -550,7 +597,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);
}
@@ -571,7 +623,8 @@
}
} else {
if (noExpandedChild || (viewHeight <= mContractedChild.getHeight()
- && (!mIsChildInGroup || !mContainingNotification.isExpanded()))) {
+ && (!mIsChildInGroup
+ || !mContainingNotification.isExpanded(true /* allowOnKeyguard */)))) {
return VISIBLE_TYPE_CONTRACTED;
} else {
return VISIBLE_TYPE_EXPANDED;
@@ -588,7 +641,6 @@
return;
}
mDark = dark;
- dark = dark && !mShowingLegacyBackground;
if (mVisibleType == VISIBLE_TYPE_CONTRACTED || !dark) {
mContractedWrapper.setDark(dark, fade, delay);
}
@@ -619,6 +671,19 @@
public void setShowingLegacyBackground(boolean showing) {
mShowingLegacyBackground = showing;
+ updateShowingLegacyBackground();
+ }
+
+ private void updateShowingLegacyBackground() {
+ if (mContractedChild != null) {
+ mContractedWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
+ }
+ if (mExpandedChild != null) {
+ mExpandedWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
+ }
+ if (mHeadsUpChild != null) {
+ mHeadsUpWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
+ }
}
public void setIsChildInGroup(boolean isChildInGroup) {
@@ -631,7 +696,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 +705,8 @@
if (mHeadsUpChild != null) {
mHeadsUpWrapper.notifyContentUpdated(entry.notification);
}
+ updateShowingLegacyBackground();
+ selectLayout(false /* animate */, true /* force */);
setDark(mDark, false /* animate */, 0 /* delay */);
}
@@ -761,7 +827,7 @@
}
public NotificationHeaderView getVisibleNotificationHeader() {
- NotificationViewWrapper wrapper = getCurrentVisibleWrapper();
+ NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
return wrapper == null ? null : wrapper.getNotificationHeader();
}
@@ -789,6 +855,7 @@
mTransformationStartVisibleType = UNDEFINED;
mVisibleType = calculateVisibleType();
updateViewVisibilities(mVisibleType);
+ updateBackgroundColor(false);
}
}
}
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 1c16bdc0..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/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index 7f8f20f..49e4ba8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -16,8 +16,19 @@
package com.android.systemui.statusbar.notification;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.graphics.Color;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.service.notification.StatusBarNotification;
+import android.support.v4.graphics.ColorUtils;
import android.view.View;
+import com.android.systemui.R;
import com.android.systemui.ViewInvertHelper;
import com.android.systemui.statusbar.phone.NotificationPanelView;
@@ -27,6 +38,11 @@
public class NotificationCustomViewWrapper extends NotificationViewWrapper {
private final ViewInvertHelper mInvertHelper;
+ private final Paint mGreyPaint = new Paint();
+ private int mBackgroundColor = 0;
+ private static final int CUSTOM_BACKGROUND_TAG = R.id.custom_background_color;
+ private boolean mShouldInvertDark;
+ private boolean mShowingLegacyBackground;
protected NotificationCustomViewWrapper(View view) {
super(view);
@@ -39,10 +55,46 @@
return;
}
super.setDark(dark, fade, delay);
- if (fade) {
- mInvertHelper.fade(dark, delay);
+ if (!mShowingLegacyBackground && mShouldInvertDark) {
+ if (fade) {
+ mInvertHelper.fade(dark, delay);
+ } else {
+ mInvertHelper.update(dark);
+ }
} else {
- mInvertHelper.update(dark);
+ mView.setLayerType(dark ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE, null);
+ if (fade) {
+ fadeGrayscale(dark, delay);
+ } else {
+ updateGrayscale(dark);
+ }
+ }
+ }
+
+ protected void fadeGrayscale(final boolean dark, long delay) {
+ startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ updateGrayscaleMatrix((float) animation.getAnimatedValue());
+ mGreyPaint.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+ mView.setLayerPaint(mGreyPaint);
+ }
+ }, dark, delay, new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!dark) {
+ mView.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+ }
+ });
+ }
+
+ protected void updateGrayscale(boolean dark) {
+ if (dark) {
+ updateGrayscaleMatrix(1f);
+ mGreyPaint.setColorFilter(
+ new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+ mView.setLayerPaint(mGreyPaint);
}
}
@@ -51,4 +103,35 @@
super.setVisible(visible);
mView.setAlpha(visible ? 1.0f : 0.0f);
}
+
+ @Override
+ public void notifyContentUpdated(StatusBarNotification notification) {
+ super.notifyContentUpdated(notification);
+ Drawable background = mView.getBackground();
+ mBackgroundColor = 0;
+ if (background instanceof ColorDrawable) {
+ mBackgroundColor = ((ColorDrawable) background).getColor();
+ mView.setBackground(null);
+ mView.setTag(CUSTOM_BACKGROUND_TAG, mBackgroundColor);
+ } else if (mView.getTag(CUSTOM_BACKGROUND_TAG) != null) {
+ mBackgroundColor = (int) mView.getTag(CUSTOM_BACKGROUND_TAG);
+ }
+ mShouldInvertDark = mBackgroundColor == 0 || isColorLight(mBackgroundColor);
+ }
+
+ private boolean isColorLight(int backgroundColor) {
+ return Color.alpha(backgroundColor) == 0
+ || ColorUtils.calculateLuminance(backgroundColor) > 0.5;
+ }
+
+ @Override
+ public int getCustomBackgroundColor() {
+ return mBackgroundColor;
+ }
+
+ @Override
+ public void setShowingLegacyBackground(boolean showing) {
+ super.setShowingLegacyBackground(showing);
+ mShowingLegacyBackground = showing;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index 842bd22..b201d8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -47,7 +47,6 @@
*/
public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
- private final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
private final PorterDuffColorFilter mIconColorFilter = new PorterDuffColorFilter(
0, PorterDuff.Mode.SRC_ATOP);
private final int mIconDarkAlpha;
@@ -178,21 +177,6 @@
}
}
- protected void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
- boolean dark, long delay, Animator.AnimatorListener listener) {
- float startIntensity = dark ? 0f : 1f;
- float endIntensity = dark ? 1f : 0f;
- ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
- animator.addUpdateListener(updateListener);
- animator.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
- animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
- animator.setStartDelay(delay);
- if (listener != null) {
- animator.addListener(listener);
- }
- animator.start();
- }
-
private void fadeIconColorFilter(final ImageView target, boolean dark, long delay) {
startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
@Override
@@ -264,10 +248,6 @@
mNotificationHeader.setOnClickListener(expandable ? onClickListener : null);
}
- private void updateGrayscaleMatrix(float intensity) {
- mGrayscaleColorMatrix.setSaturation(1 - intensity);
- }
-
private static int interpolateColor(int source, int target, float t) {
int aSource = Color.alpha(source);
int rSource = Color.red(source);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index 4738657..6ef61ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification;
+import android.graphics.Color;
import android.widget.ImageView;
import com.android.internal.util.NotificationColorUtil;
@@ -38,4 +39,12 @@
public static float interpolate(float start, float end, float amount) {
return start * (1.0f - amount) + end * amount;
}
+
+ public static int interpolateColors(int startColor, int endColor, float amount) {
+ return Color.argb(
+ (int) interpolate(Color.alpha(startColor), Color.alpha(endColor), amount),
+ (int) interpolate(Color.red(startColor), Color.red(endColor), amount),
+ (int) interpolate(Color.green(startColor), Color.green(endColor), amount),
+ (int) interpolate(Color.blue(startColor), Color.blue(endColor), amount));
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 0df0d26..ebff69d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -16,13 +16,19 @@
package com.android.systemui.statusbar.notification;
+import android.animation.Animator;
+import android.animation.ValueAnimator;
import android.content.Context;
+import android.graphics.ColorMatrix;
import android.service.notification.StatusBarNotification;
import android.view.NotificationHeaderView;
import android.view.View;
+import com.android.systemui.Interpolators;
import com.android.systemui.statusbar.CrossFadeHelper;
+import com.android.systemui.statusbar.NotificationContentView;
import com.android.systemui.statusbar.TransformableView;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
/**
* Wraps the actual notification content view; used to implement behaviors which are different for
@@ -30,6 +36,7 @@
*/
public abstract class NotificationViewWrapper implements TransformableView {
+ protected final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
protected final View mView;
protected boolean mDark;
protected boolean mDarkInitialized = false;
@@ -75,6 +82,26 @@
mDarkInitialized = false;
};
+
+ protected void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
+ boolean dark, long delay, Animator.AnimatorListener listener) {
+ float startIntensity = dark ? 0f : 1f;
+ float endIntensity = dark ? 1f : 0f;
+ ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
+ animator.addUpdateListener(updateListener);
+ animator.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
+ animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+ animator.setStartDelay(delay);
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+ animator.start();
+ }
+
+ protected void updateGrayscaleMatrix(float intensity) {
+ mGrayscaleColorMatrix.setSaturation(1 - intensity);
+ }
+
/**
* Update the appearance of the expand button.
*
@@ -122,4 +149,11 @@
mView.animate().cancel();
mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
}
+
+ public int getCustomBackgroundColor() {
+ return 0;
+ }
+
+ public void setShowingLegacyBackground(boolean showing) {
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
index 5ab441d..d3393b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification;
+import android.text.Layout;
import android.text.TextUtils;
import android.util.Pools;
import android.view.View;
@@ -28,14 +29,13 @@
private static Pools.SimplePool<TextViewTransformState> sInstancePool
= new Pools.SimplePool<>(40);
- private CharSequence mText;
+ private TextView mText;
@Override
public void initFrom(View view) {
super.initFrom(view);
if (view instanceof TextView) {
- TextView txt = (TextView) view;
- mText = txt.getText();
+ mText = (TextView) view;
}
}
@@ -43,11 +43,27 @@
protected boolean sameAs(TransformState otherState) {
if (otherState instanceof TextViewTransformState) {
TextViewTransformState otherTvs = (TextViewTransformState) otherState;
- return TextUtils.equals(otherTvs.mText, mText);
+ if(TextUtils.equals(otherTvs.mText.getText(), mText.getText())) {
+ int ownEllipsized = getEllipsisCount();
+ int otherEllipsized = otherTvs.getEllipsisCount();
+ return ownEllipsized == otherEllipsized;
+ }
}
return super.sameAs(otherState);
}
+ private int getEllipsisCount() {
+ Layout l = mText.getLayout();
+ if (l != null) {
+ int lines = l.getLineCount();
+ if (lines > 0) {
+ // we only care about the first line
+ return l.getEllipsisCount(0);
+ }
+ }
+ return 0;
+ }
+
public static TextViewTransformState obtain() {
TextViewTransformState instance = sInstancePool.acquire();
if (instance != null) {
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..9c6f2c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -65,7 +65,7 @@
import java.util.List;
public class NotificationPanelView extends PanelView implements
- ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
+ ExpandableView.OnHeightChangedListener,
View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener,
HeadsUpManager.OnHeadsUpChangedListener {
@@ -222,6 +222,7 @@
@Override
public void onInflated(View v) {
mQsContainer = (QSContainer) v.findViewById(R.id.quick_settings_container);
+ mQsContainer.setPanelView(NotificationPanelView.this);
mQsContainer.getHeader().setOnClickListener(NotificationPanelView.this);
}
});
@@ -247,7 +248,7 @@
final int height = bottom - top;
final int oldHeight = oldBottom - oldTop;
if (height != oldHeight) {
- onScrollChanged();
+ onQsHeightChanged();
}
}
});
@@ -547,7 +548,7 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (mBlockTouches) {
+ if (mBlockTouches || mQsContainer.isCustomizing()) {
return false;
}
initDownStates(event);
@@ -707,7 +708,7 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
- if (mBlockTouches) {
+ if (mBlockTouches || mQsContainer.isCustomizing()) {
return false;
}
initDownStates(event);
@@ -906,18 +907,6 @@
}
@Override
- public void onOverscrolled(float lastTouchX, float lastTouchY, int amount) {
- if (mIntercepting && shouldQuickSettingsIntercept(lastTouchX, lastTouchY,
- -1 /* yDiff: Not relevant here */)) {
- mQsTracking = true;
- onQsExpansionStarted(amount);
- mInitialHeightOnTouch = mQsExpansionHeight;
- mInitialTouchY = mLastTouchY;
- mInitialTouchX = mLastTouchX;
- }
- }
-
- @Override
public void onOverscrollTopChanged(float amount, boolean isRubberbanded) {
cancelQsAnimation();
if (!mQsExpansionEnabled) {
@@ -1397,7 +1386,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 +1442,7 @@
&& mShadeEmpty) {
notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight()
+ mNotificationStackScroller.getBottomStackPeekSize()
- + mNotificationStackScroller.getCollapseSecondCardPadding();
+ + mNotificationStackScroller.getBottomStackSlowDownHeight();
}
int maxQsHeight = mQsMaxExpansionHeight;
@@ -1468,7 +1457,7 @@
+ notificationHeight;
if (totalHeight > mNotificationStackScroller.getHeight()) {
float fullyCollapsedHeight = maxQsHeight
- + mNotificationStackScroller.getMinStackHeight();
+ + mNotificationStackScroller.getLayoutMinHeight();
totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight());
}
return (int) totalHeight;
@@ -1485,7 +1474,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;
@@ -1719,9 +1708,10 @@
public void onReset(ExpandableView view) {
}
- @Override
- public void onScrollChanged() {
+ public void onQsHeightChanged() {
+ mQsMaxExpansionHeight = mQsContainer.getDesiredHeight();
if (mQsExpanded) {
+ mQsExpansionHeight = mQsMaxExpansionHeight;
requestScrollerTopPaddingUpdate(false /* animate */);
requestPanelHeightUpdate();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 6d90e5c..f0df706 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -24,21 +24,24 @@
import android.view.ViewStub;
import android.view.WindowInsets;
import android.widget.FrameLayout;
-
+import com.android.systemui.DensityContainer;
import com.android.systemui.R;
+import com.android.systemui.qs.QSContainer;
+import com.android.systemui.qs.customize.QSCustomizer;
/**
* The container with notification stack scroller and quick settings inside.
*/
public class NotificationsQuickSettingsContainer extends FrameLayout
- implements ViewStub.OnInflateListener {
+ implements ViewStub.OnInflateListener, DensityContainer.InflateListener {
- private View mQsContainer;
+ private DensityContainer mQsContainer;
private View mUserSwitcher;
private View mStackScroller;
private View mKeyguardStatusBar;
private boolean mInflated;
private boolean mQsExpanded;
+ private boolean mCustomizerAnimating;
public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -47,7 +50,8 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mQsContainer = findViewById(R.id.qs_density_container);
+ mQsContainer = (DensityContainer) findViewById(R.id.qs_density_container);
+ mQsContainer.addInflateListener(this);
mStackScroller = findViewById(R.id.notification_stack_scroller);
mKeyguardStatusBar = findViewById(R.id.keyguard_header);
ViewStub userSwitcher = (ViewStub) findViewById(R.id.keyguard_user_switcher);
@@ -80,8 +84,9 @@
boolean userSwitcherVisible = mInflated && mUserSwitcher.getVisibility() == View.VISIBLE;
boolean statusBarVisible = mKeyguardStatusBar.getVisibility() == View.VISIBLE;
- View stackQsTop = mQsExpanded ? mStackScroller : mQsContainer;
- View stackQsBottom = !mQsExpanded ? mStackScroller : mQsContainer;
+ final boolean qsBottom = mQsExpanded && !mCustomizerAnimating;
+ View stackQsTop = qsBottom ? mStackScroller : mQsContainer;
+ View stackQsBottom = !qsBottom ? mStackScroller : mQsContainer;
// Invert the order of the scroll view and user switcher such that the notifications receive
// touches first but the panel gets drawn above.
if (child == mQsContainer) {
@@ -117,10 +122,23 @@
}
}
+ @Override
+ public void onInflated(View v) {
+ QSCustomizer customizer = ((QSContainer) v).getCustomizer();
+ customizer.setContainer(this);
+ }
+
public void setQsExpanded(boolean expanded) {
if (mQsExpanded != expanded) {
mQsExpanded = expanded;
invalidate();
}
}
+
+ public void setCustomizerAnimating(boolean isAnimating) {
+ if (mCustomizerAnimating != isAnimating) {
+ mCustomizerAnimating = isAnimating;
+ invalidate();
+ }
+ }
}
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..7856f6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -772,10 +772,21 @@
ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
mScrimController = SystemUIFactory.getInstance().createScrimController(
- scrimBehind, scrimInFront, headsUpScrim, mScrimSrcModeEnabled);
+ scrimBehind, scrimInFront, headsUpScrim);
+ if (mScrimSrcModeEnabled) {
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE;
+ mScrimController.setDrawBehindAsSrc(asSrc);
+ mStackScroller.setDrawBackgroundAsSrc(asSrc);
+ }
+ };
+ mBackdrop.setOnVisibilityChangedRunnable(runnable);
+ runnable.run();
+ }
mHeadsUpManager.addListener(mScrimController);
mStackScroller.setScrimController(mScrimController);
- mScrimController.setBackDropView(mBackdrop);
mStatusBarView.setScrimController(mScrimController);
mDozeScrimController = new DozeScrimController(mScrimController, context);
@@ -995,7 +1006,6 @@
SignalClusterView signalCluster =
(SignalClusterView) containerView.findViewById(R.id.signal_cluster);
if (signalCluster != null) {
- mNetworkController.addSignalCallback(signalCluster);
signalCluster.setSecurityController(mSecurityController);
signalCluster.setNetworkController(mNetworkController);
}
@@ -1467,6 +1477,9 @@
mStackScroller.removeView(remove);
mStackScroller.setChildTransferInProgress(false);
}
+
+ removeNotificationChildren();
+
for (int i=0; i<toShow.size(); i++) {
View v = toShow.get(i);
if (v.getParent() == null) {
@@ -1474,6 +1487,8 @@
}
}
+ addNotificationChildrenAndSort();
+
// So after all this work notifications still aren't sorted correctly.
// Let's do that now by advancing through toShow and mStackScroller in
// lock-step, making sure mStackScroller matches what we see in toShow.
@@ -1495,9 +1510,6 @@
}
- // lets handle the child notifications now
- updateNotificationShadeForChildren();
-
// clear the map again for the next usage
mTmpChildOrderMap.clear();
@@ -1523,34 +1535,7 @@
&& !ONLY_CORE_APPS);
}
- private void updateNotificationShadeForChildren() {
- // First let's remove all children which don't belong in the parents
- ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
- for (int i = 0; i < mStackScroller.getChildCount(); i++) {
- View view = mStackScroller.getChildAt(i);
- if (!(view instanceof ExpandableNotificationRow)) {
- // We don't care about non-notification views.
- continue;
- }
-
- ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
- List<ExpandableNotificationRow> children = parent.getNotificationChildren();
- List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
-
- if (children != null) {
- toRemove.clear();
- for (ExpandableNotificationRow childRow : children) {
- if (orderedChildren == null || !orderedChildren.contains(childRow)) {
- toRemove.add(childRow);
- }
- }
- for (ExpandableNotificationRow remove : toRemove) {
- parent.removeChildNotification(remove);
- mStackScroller.notifyGroupChildRemoved(remove);
- }
- }
- }
-
+ private void addNotificationChildrenAndSort() {
// Let's now add all notification children which are missing
boolean orderChanged = false;
for (int i = 0; i < mStackScroller.getChildCount(); i++) {
@@ -1581,6 +1566,39 @@
}
}
+ private void removeNotificationChildren() {
+ // First let's remove all children which don't belong in the parents
+ ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
+ for (int i = 0; i < mStackScroller.getChildCount(); i++) {
+ View view = mStackScroller.getChildAt(i);
+ if (!(view instanceof ExpandableNotificationRow)) {
+ // We don't care about non-notification views.
+ continue;
+ }
+
+ ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
+ List<ExpandableNotificationRow> children = parent.getNotificationChildren();
+ List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
+
+ if (children != null) {
+ toRemove.clear();
+ for (ExpandableNotificationRow childRow : children) {
+ if (orderedChildren == null || !orderedChildren.contains(childRow)) {
+ toRemove.add(childRow);
+ }
+ }
+ for (ExpandableNotificationRow remove : toRemove) {
+ parent.removeChildNotification(remove);
+ if (mNotificationData.get(remove.getStatusBarNotification().getKey()) == null) {
+ // We only want to add an animation if the view is completely removed
+ // otherwise it's just a transfer
+ mStackScroller.notifyGroupChildRemoved(remove);
+ }
+ }
+ }
+ }
+ }
+
@Override
public void addQsTile(ComponentName tile) {
mQSPanel.getHost().addTile(tile);
@@ -1597,8 +1615,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 +3573,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..b29c807 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -296,8 +296,7 @@
mHost = host;
host.setHeaderView(this);
mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
- mHeaderQsPanel.setMaxTiles(5);
- mHeaderQsPanel.setHost(host);
+ mHeaderQsPanel.setHost(host, null /* No customization in header */);
setUserInfoController(host.getUserInfoController());
setBatteryController(host.getBatteryController());
setNextAlarmController(host.getNextAlarmController());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index fe76ae7..1a557e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -30,7 +30,6 @@
import android.view.animation.PathInterpolator;
import com.android.systemui.R;
-import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.ScrimView;
@@ -75,8 +74,6 @@
private long mAnimationDelay;
private Runnable mOnAnimationFinished;
private final Interpolator mInterpolator = new DecelerateInterpolator();
- private BackDropView mBackDropView;
- private boolean mScrimSrcEnabled;
private boolean mDozing;
private float mDozeInFrontAlpha;
private float mDozeBehindAlpha;
@@ -90,14 +87,12 @@
private boolean mSkipFirstFrame;
private boolean mDontAnimateBouncerChanges;
- public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim,
- boolean scrimSrcEnabled) {
+ public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim) {
mScrimBehind = scrimBehind;
mScrimInFront = scrimInFront;
mHeadsUpScrim = headsUpScrim;
final Context context = scrimBehind.getContext();
mUnlockMethodCache = UnlockMethodCache.getInstance(context);
- mScrimSrcEnabled = scrimSrcEnabled;
updateHeadsUpScrim(false);
}
@@ -378,19 +373,7 @@
return scrim.getTag(TAG_KEY_ANIM) != null;
}
- public void setBackDropView(BackDropView backDropView) {
- mBackDropView = backDropView;
- mBackDropView.setOnVisibilityChangedRunnable(new Runnable() {
- @Override
- public void run() {
- updateScrimBehindDrawingMode();
- }
- });
- updateScrimBehindDrawingMode();
- }
-
- private void updateScrimBehindDrawingMode() {
- boolean asSrc = mBackDropView.getVisibility() != View.VISIBLE && mScrimSrcEnabled;
+ public void setDrawBehindAsSrc(boolean asSrc) {
mScrimBehind.setDrawAsSrc(asSrc);
}
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/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index b6a3234..cedc3c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -362,6 +362,19 @@
switchToUserId(id);
}
+ public void switchTo(int userId) {
+ final int count = mUsers.size();
+ for (int i = 0; i < count; ++i) {
+ UserRecord record = mUsers.get(i);
+ if (record.info != null && record.info.id == userId) {
+ switchTo(record);
+ return;
+ }
+ }
+
+ Log.e(TAG, "Couldn't switch to user, id=" + userId);
+ }
+
private void switchToUserId(int id) {
try {
pauseRefreshUsers();
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/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 7955733..9d50ab4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -511,7 +511,7 @@
break;
}
ExpandableNotificationRow child = mChildren.get(i);
- float childHeight = child.isExpanded()
+ float childHeight = child.isExpanded(true /* allowOnKeyguard */)
? child.getMaxExpandHeight()
: child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */);
maxContentHeight += childHeight;
@@ -532,7 +532,7 @@
int childCount = mChildren.size();
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
- float childHeight = child.isExpanded()
+ float childHeight = child.isExpanded(true /* allowOnKeyguard */)
? child.getMaxExpandHeight()
: child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */);
float singleLineHeight = child.getShowingLayout().getMinHeight(
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..cca3746 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -18,7 +18,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TimeAnimator;
@@ -48,6 +47,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;
@@ -322,6 +323,7 @@
}
}
};
+ private PorterDuffXfermode mSrcMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -357,12 +359,13 @@
mDebugPaint.setStyle(Paint.Style.STROKE);
}
mFalsingManager = FalsingManager.getInstance(context);
- mBackgroundPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
}
@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 +421,14 @@
.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);
+ }
+
+ public void setDrawBackgroundAsSrc(boolean asSrc) {
+ mBackgroundPaint.setXfermode(asSrc ? mSrcMode : null);
+ invalidate();
}
private void notifyHeightChangeListener(ExpandableView view) {
@@ -509,14 +514,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 +596,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 +609,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 +652,8 @@
return mBottomStackPeekSize;
}
- public int getCollapseSecondCardPadding() {
- return mCollapseSecondCardPadding;
+ public int getBottomStackSlowDownHeight() {
+ return mBottomStackSlowDownHeight;
}
public void setLongPressListener(SwipeHelper.LongPressListener listener) {
@@ -734,6 +718,7 @@
if (targetLeft == 0 && mCurrIconRow != null) {
mCurrIconRow.resetState();
+ mCurrIconRow = null;
if (mGearExposedView != null && mGearExposedView == mTranslatingParentView) {
mGearExposedView = null;
}
@@ -793,12 +778,15 @@
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
ExpandableNotificationRow parent = row.getNotificationParent();
- if (mGearExposedView != null && parent != null
- && parent.areChildrenExpanded() && mGearExposedView == parent) {
+ if (parent != null && parent.areChildrenExpanded()
+ && (mGearExposedView == parent
+ || (parent.getNotificationChildren().size() == 1
+ && parent.isClearable()))) {
// In this case the group is expanded and showing the gear for the
// group, further interaction should apply to the group, not any
- // child notifications so we use the parent of the child.
- child = row.getNotificationParent();
+ // child notifications so we use the parent of the child. We also do the same
+ // if we only have a single child.
+ child = parent;
}
}
return child;
@@ -876,7 +864,7 @@
public boolean canChildBeExpanded(View v) {
return v instanceof ExpandableNotificationRow
&& ((ExpandableNotificationRow) v).isExpandable()
- && !((ExpandableNotificationRow) v).isHeadsUp();
+ && (mIsExpanded || !((ExpandableNotificationRow) v).isPinned());
}
public void setUserExpandedChild(View v, boolean userExpanded) {
@@ -1850,7 +1838,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 +1852,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 +1873,7 @@
final int firstChildMinHeight = firstChild != null ? (int) firstChild.getMinHeight()
: mCollapsedSize;
return mIntrinsicPadding + firstChildMinHeight + mBottomStackPeekSize
- + mCollapseSecondCardPadding;
+ + mBottomStackSlowDownHeight;
}
private int clampPadding(int desiredPadding) {
@@ -1994,7 +1987,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 +2167,6 @@
private void onViewAddedInternal(View child) {
updateHideSensitiveForChild(child);
- mStackScrollAlgorithm.notifyChildrenChanged(this);
((ExpandableView) child).setOnHeightChangedListener(this);
generateAddAnimation(child, false /* fromMoreCard */);
updateAnimationState(child);
@@ -2643,12 +2634,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 +2646,10 @@
public void onExpansionStarted() {
mIsExpansionChanging = true;
- mStackScrollAlgorithm.onExpansionStarted(mCurrentStackScrollState);
}
public void onExpansionStopped() {
mIsExpansionChanging = false;
- mStackScrollAlgorithm.onExpansionStopped();
if (!mIsExpanded) {
mOwnScrollY = 0;
@@ -2732,7 +2717,6 @@
if (mIsExpanded && mAnimationsEnabled) {
mRequestViewResizeAnimationOnLayout = true;
}
- mStackScrollAlgorithm.onReset(view);
updateAnimationState(view);
updateChronometerForChild(view);
}
@@ -3163,15 +3147,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 +3375,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 +3391,7 @@
// Reset check for drag gesture
mCheckForDrag = null;
+ mCurrIconRow = null;
// Slide back any notifications that might be showing a gear
resetExposedGearView();
@@ -3424,9 +3400,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 +3413,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 +3441,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 +3456,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 +3473,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 +3483,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 +3542,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 fb7fa4d..285dfd1 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -25,6 +25,9 @@
import android.widget.TextView;
import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+import com.android.systemui.SystemUIApplication;
+import com.android.systemui.recents.Recents;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
@@ -47,6 +50,7 @@
private TextView mPlayPauseDescriptionTextView;
private View mCloseButtonView;
private View mCloseDescriptionView;
+ private boolean mPipMovedToFullscreen;
private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
@Override
@@ -66,6 +70,7 @@
@Override
public void onClick(View v) {
mPipManager.movePipToFullscreen();
+ mPipMovedToFullscreen = true;
finish();
}
});
@@ -164,7 +169,9 @@
}
private void restorePipAndFinish() {
- mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
+ if (!mPipMovedToFullscreen) {
+ mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
+ }
finish();
}
@@ -214,4 +221,18 @@
mPipManager.suspendPipResizing(
PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
}
+
+ @Override
+ public void finish() {
+ super.finish();
+ if (mPipManager.isRecentsShown() && !mPipMovedToFullscreen) {
+ SystemUI[] services = ((SystemUIApplication) getApplication()).getServices();
+ for (int i = services.length - 1; i >= 0; i--) {
+ if (services[i] instanceof Recents) {
+ ((Recents) services[i]).showRecents(false, null);
+ break;
+ }
+ }
+ }
+ }
}
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 077b121..65654a8 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -24,334 +24,1734 @@
// Known visual elements: views or controls.
enum View {
+ // Unknown view
VIEW_UNKNOWN = 0;
+
+ // OBSOLETE
MAIN_SETTINGS = 1;
+
+ // OPEN: Settings > Accessibility
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACCESSIBILITY = 2;
+
+ // OPEN: Settings > Accessibility > Captions
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACCESSIBILITY_CAPTION_PROPERTIES = 3;
+
+ // OPEN: Settings > Accessibility > [Service]
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACCESSIBILITY_SERVICE = 4;
+
+ // OPEN: Settings > Accessibility > Color correction
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACCESSIBILITY_TOGGLE_DALTONIZER = 5;
+
+ // OPEN: Settings > Accessibility > Accessibility shortcut
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE = 6;
+
+ // OPEN: Settings > Accessibility > Magnification gestures
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 7;
+
+ // OPEN: Settings > Accounts
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACCOUNT = 8;
+
+ // OPEN: Settings > Accounts > [Single Account Sync Settings]
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACCOUNTS_ACCOUNT_SYNC = 9;
+
+ // OPEN: Settings > Accounts > Add an account
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY = 10;
+
+ // OPEN: Settings > Accounts > [List of accounts when more than one]
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACCOUNTS_MANAGE_ACCOUNTS = 11;
+
+ // OPEN: Settings > Cellular network settings > APNs
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
APN = 12;
+
+ // OPEN: Settings > More > Cellular network settings > APNs > [Edit APN]
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
APN_EDITOR = 13;
+
+ // OBSOLETE
APP_OPS_DETAILS = 14;
+
+ // OBSOLETE
APP_OPS_SUMMARY = 15;
+
+ // OBSOLETE
APPLICATION = 16;
+
+ // OPEN: Settings > Apps > Configure apps > App links > [App]
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
APPLICATIONS_APP_LAUNCH = 17;
+
+ // OBSOLETE
APPLICATIONS_APP_PERMISSION = 18;
+
+ // OPEN: Settings > Internal storage > Apps storage > [App]
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
APPLICATIONS_APP_STORAGE = 19;
+
+ // OPEN: Settings > Apps > [App info]
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
APPLICATIONS_INSTALLED_APP_DETAILS = 20;
+
+ // OPEN: Settings > Memory > App usage > [App Memory usage]
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
APPLICATIONS_PROCESS_STATS_DETAIL = 21;
+
+ // OBSOLETE
APPLICATIONS_PROCESS_STATS_MEM_DETAIL = 22;
+
+ // OPEN: Settings > Memory > App usage
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
APPLICATIONS_PROCESS_STATS_UI = 23;
+
+ // OPEN: Settings > Bluetooth
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
BLUETOOTH = 24;
+
+ // OPEN: Choose Bluetooth device (ex: when sharing)
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
BLUETOOTH_DEVICE_PICKER = 25;
+
+ // OBSOLETE
BLUETOOTH_DEVICE_PROFILES = 26;
+
+ // OPEN: Settings > Security > Choose screen lock
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
CHOOSE_LOCK_GENERIC = 27;
+
+ // OPEN: Settings > Security > Choose screen lock > Choose your password
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
CHOOSE_LOCK_PASSWORD = 28;
+
+ // OPEN: Settings > Security > Choose screen lock > Choose your pattern
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
CHOOSE_LOCK_PATTERN = 29;
+
+ // OPEN: Settings > Security > Choose screen lock > Confirm your password
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
CONFIRM_LOCK_PASSWORD = 30;
+
+ // OPEN: Settings > Security > Choose screen lock > Confirm your pattern
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
CONFIRM_LOCK_PATTERN = 31;
+
+ // OPEN: Settings > Security > Encrypt phone
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
CRYPT_KEEPER = 32;
+
+ // OPEN: Settings > Security > Encrypt phone > Confirm
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
CRYPT_KEEPER_CONFIRM = 33;
+
+ // OPEN: Settings > Search results
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
DASHBOARD_SEARCH_RESULTS = 34;
+
+ // OPEN: Settings (Root page)
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
DASHBOARD_SUMMARY = 35;
+
+ // OBSOLETE
DATA_USAGE = 36;
+
+ // OPEN: Settings > Data usage
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
DATA_USAGE_SUMMARY = 37;
+
+ // OPEN: Settings > Date & time
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
DATE_TIME = 38;
+
+ // OPEN: Settings > Developer options
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
DEVELOPMENT = 39;
+
+ // OPEN: Settings > About phone
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
DEVICEINFO = 40;
+
+ // OPEN: Settings > About phone > Status > IMEI information
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
DEVICEINFO_IMEI_INFORMATION = 41;
+
+ // OPEN: Settings > Internal storage
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
DEVICEINFO_STORAGE = 42;
+
+ // OPEN: Settings > About phone > Status > SIM status
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
DEVICEINFO_SIM_STATUS = 43;
+
+ // OPEN: Settings > About phone > Status
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
DEVICEINFO_STATUS = 44;
+
+ // OBSOLETE
DEVICEINFO_USB = 45;
+
+ // OPEN: Settings > Display
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
DISPLAY = 46;
+
+ // OPEN: Settings > Display > Daydream
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
DREAM = 47;
+
+ // OPEN: Settings > Security > Screen lock > Secure start-up
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ENCRYPTION = 48;
+
+ // OPEN: Settings > Security > Nexus Imprint
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
FINGERPRINT = 49;
+
+ // OBSOLETE
FINGERPRINT_ENROLL = 50;
+
+ // OPEN: Settings > Battery > History details
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
FUELGAUGE_BATTERY_HISTORY_DETAIL = 51;
+
+ // OPEN: Settings > Battery > Battery saver
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
FUELGAUGE_BATTERY_SAVER = 52;
+
+ // OPEN: Settings > Battery > [App Use details]
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
FUELGAUGE_POWER_USAGE_DETAIL = 53;
+
+ // OPEN: Settings > Battery
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
FUELGAUGE_POWER_USAGE_SUMMARY = 54;
+
+ // OPEN: Settings > Home
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
HOME = 55;
+
+ // OPEN: Settings > Security > SIM card lock settings
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ICC_LOCK = 56;
+
+ // OPEN: Settings > Language & input
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
INPUTMETHOD_LANGUAGE = 57;
+
+ // OPEN: Settings > Language & input > Physical keyboard
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
INPUTMETHOD_KEYBOARD = 58;
+
+ // OPEN: Settings > Language & input > Spell checker
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
INPUTMETHOD_SPELL_CHECKERS = 59;
+
+ // OBSOLETE
INPUTMETHOD_SUBTYPE_ENABLER = 60;
+
+ // OPEN: Settings > Language & input > Personal dictionary
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
INPUTMETHOD_USER_DICTIONARY = 61;
+
+ // OPEN: Settings > Language & input > Add word
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
INPUTMETHOD_USER_DICTIONARY_ADD_WORD = 62;
+
+ // OPEN: Settings > Location
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
LOCATION = 63;
+
+ // OPEN: Settings > Location > Location mode
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
LOCATION_MODE = 64;
+
+ // OPEN: Settings > Apps
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
MANAGE_APPLICATIONS = 65;
+
+ // OPEN: Settings > Backup & reset > Factory data reset
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
MASTER_CLEAR = 66;
+
+ // OPEN: Settings > Backup & reset > Factory data reset > Confirm
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
MASTER_CLEAR_CONFIRM = 67;
+
+ // OPEN: Settings > Data usage > Network restrictions
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
NET_DATA_USAGE_METERED = 68;
+
+ // OPEN: Settings > More > Android Beam
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
NFC_BEAM = 69;
+
+ // OPEN: Settings > Tap & pay
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
NFC_PAYMENT = 70;
+
+ // OPEN: Settings > Sound & notification
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
NOTIFICATION = 71;
+
+ // OPEN: Settings > Sound & notification > App notifications > [App]
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
NOTIFICATION_APP_NOTIFICATION = 72;
+
+ // OPEN: Settings > Sound & notification > Other sounds
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
NOTIFICATION_OTHER_SOUND = 73;
+
+ // OBSOLETE
NOTIFICATION_REDACTION = 74;
+
+ // OPEN: Settings Widget > Notification log
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
NOTIFICATION_STATION = 75;
+
+ // OPEN: Settings > Sound & notification > Do not disturb
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
NOTIFICATION_ZEN_MODE = 76;
+
+ // OPEN: OBSOLETE
OWNER_INFO = 77;
+
+ // OPEN: Print job notification > Print job settings
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
PRINT_JOB_SETTINGS = 78;
+
+ // OPEN: Settings > Printing > [Print Service]
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
PRINT_SERVICE_SETTINGS = 79;
+
+ // OPEN: Settings > Printing
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
PRINT_SETTINGS = 80;
+
+ // OPEN: Settings > Backup & reset
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
PRIVACY = 81;
+
+ //OBSOLETE
PROXY_SELECTOR = 82;
+
+ // OPEN: Settings > Backup & reset > Network settings reset
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
RESET_NETWORK = 83;
+
+ // OPEN: Settings > Backup & reset > Network settings reset > Confirm
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
RESET_NETWORK_CONFIRM = 84;
+
+ // OPEN: Settings > Developer Options > Running Services
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
RUNNING_SERVICE_DETAILS = 85;
+
+ // OPEN: Settings > Security > Screen pinning
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
SCREEN_PINNING = 86;
+
+ // OPEN: Settings > Security
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
SECURITY = 87;
+
+ // OPEN: Settings > SIM cards
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
SIM = 88;
+
+ // OBSOLETE
TESTING = 89;
+
+ // OPEN: Settings > More > Tethering & portable hotspot
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
TETHER = 90;
+
+ // OPEN: Settings > Security > Trust agents
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
TRUST_AGENT = 91;
+
+ // OPEN: Settings > Security > Trusted credentials
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
TRUSTED_CREDENTIALS = 92;
+
+ // OPEN: Settings > Language & input > TTS output > [Engine] > Settings
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
TTS_ENGINE_SETTINGS = 93;
+
+ // OPEN: Settings > Language & input > Text-to-speech output
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
TTS_TEXT_TO_SPEECH = 94;
+
+ // OPEN: Settings > Security > Apps with usage access
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
USAGE_ACCESS = 95;
+
+ // OPEN: Settings > Users
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
USER = 96;
+
+ // OPEN: Settings > Users > [Restricted profile app & content access]
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
USERS_APP_RESTRICTIONS = 97;
+
+ // OPEN: Settings > Users > [User settings]
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
USER_DETAILS = 98;
+
+ // OBSOLETE
VOICE_INPUT = 99;
+
+ // OPEN: Settings > More > VPN
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
VPN = 100;
+
+ // OPEN: Settings > Display > Choose wallpaper from
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
WALLPAPER_TYPE = 101;
+
+ // OPEN: Settings > Display > Cast
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
WFD_WIFI_DISPLAY = 102;
+
+ // OPEN: Settings > Wi-Fi
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
WIFI = 103;
+
+ // OPEN: Settings > Wi-Fi > Advanced Wi-Fi
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
WIFI_ADVANCED = 104;
+
+ // OPEN: Settings > More > Wi-Fi Calling
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
WIFI_CALLING = 105;
+
+ // OPEN: Settings > Wi-Fi > Saved networks
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
WIFI_SAVED_ACCESS_POINTS = 106;
+
+ // OBSOLETE
WIFI_APITEST = 107;
+
+ // OBSOLETE
WIFI_INFO = 108;
+
+ // OPEN: Settings > Wi-Fi > Advanced Wi-Fi > Wi-Fi Direct
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
WIFI_P2P = 109;
+
+ // OPEN: Settings > More
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
WIRELESS = 110;
+
+ // OPEN: Quick Settings Panel
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
QS_PANEL = 111;
+
+ // OPEN: QS Airplane mode tile shown
+ // ACTION: QS Airplane mode tile tapped
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.46
QS_AIRPLANEMODE = 112;
+
+ // OPEN: QS Bluetooth tile shown
+ // ACTION: QS Bluetooth tile tapped
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.46
QS_BLUETOOTH = 113;
+
+ // OPEN: QS Cast tile shown
+ // ACTION: QS Cast tile tapped
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.46
QS_CAST = 114;
+
+ // OPEN: QS Cellular tile shown
+ // ACTION: QS Cellular tile tapped
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.46
QS_CELLULAR = 115;
+
+ // OPEN: QS Color inversion tile shown
+ // ACTION: QS Color inversion tile tapped
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.46
QS_COLORINVERSION = 116;
+
+ // OPEN: QS Cellular tile > Cellular detail panel
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.46
QS_DATAUSAGEDETAIL = 117;
+
+ // OPEN: QS Do not disturb tile shown
+ // ACTION: QS Do not disturb tile tapped
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.46
QS_DND = 118;
+
+ // OPEN: QS Flashlight tile shown
+ // ACTION: QS Flashlight tile tapped
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.46
QS_FLASHLIGHT = 119;
+
+ // OPEN: QS Hotspot tile shown
+ // ACTION: QS Hotspot tile tapped
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.46
QS_HOTSPOT = 120;
+
+ // OPEN: QS 3P tile shown
+ // ACTION: QS 3P tile tapped
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.46
QS_INTENT = 121;
+
+ // OPEN: QS Location tile shown
+ // ACTION: QS Location tile tapped
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.46
QS_LOCATION = 122;
+
+ // OPEN: QS Rotation tile shown
+ // ACTION: QS Rotation tile tapped
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.46
QS_ROTATIONLOCK = 123;
+
+ // OBSOLETE
QS_USERDETAILITE = 124;
+
+ // OPEN: QS User list panel
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.46
QS_USERDETAIL = 125;
+
+ // OPEN: QS WiFi tile shown
+ // ACTION: QS WiFi tile tapped
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.46
QS_WIFI = 126;
+
+ // OPEN: Notification Panel (including lockscreen)
+ // CATEGORY: NOTIFICATION
+ // OS: 5.1.1
+ // GMS: 7.5.26
NOTIFICATION_PANEL = 127;
+
+ // OPEN: Notification in panel became visible.
+ // PACKAGE: App that posted the notification.
+ // ACTION: Notification is tapped.
+ // PACKAGE: App that posted the notification
+ // DETAIL: Notification is expanded by user.
+ // PACKAGE: App that posted the notification
+ // DISMISS: Notification is dismissed.
+ // PACKAGE: App that posted the notification
+ // SUBTYPE: Dismiss reason from NotificationManagerService.java
+ // CATEGORY: NOTIFICATION
+ // OS: 5.1.1
+ // GMS: 7.5.26
NOTIFICATION_ITEM = 128;
+
+ // ACTION: User tapped notification action
+ // PACKAGE: App that posted the notification
+ // SUBTYPE: Index of action on notification
+ // CATEGORY: NOTIFICATION
+ // OS: 5.0
+ // GMS: 7.5.26
NOTIFICATION_ITEM_ACTION = 129;
+
+ // OPEN: Settings > Apps > Configure apps > App permissions
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
APPLICATIONS_ADVANCED = 130;
+
+ // OPEN: Settings > Location > Scanning
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
LOCATION_SCANNING = 131;
+
+ // OBSOLETE
MANAGE_APPLICATIONS_ALL = 132;
+
+ // OPEN: Settings > Sound & notification > App notifications
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
MANAGE_APPLICATIONS_NOTIFICATIONS = 133;
+
+ // ACTION: Settings > Wi-Fi > Overflow > Add Network
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_WIFI_ADD_NETWORK = 134;
+
+ // ACTION: Settings > Wi-Fi > [Long press network] > Connect to network
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_WIFI_CONNECT = 135;
+
+ // ACTION: Settings > Wi-Fi > Overflow > Refresh
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_WIFI_FORCE_SCAN = 136;
+
+ // ACTION: Settings > Wi-Fi > [Long press network] > Forget network
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_WIFI_FORGET = 137;
+
+ // ACTION: Settings > Wi-Fi > Toggle off
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_WIFI_OFF = 138;
+
+ // ACTION: Settings > Wi-Fi > Toggle on
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_WIFI_ON = 139;
+
+ // OBSOLETE
MANAGE_PERMISSIONS = 140;
+
+ // OPEN: Settings > Sound & notification > DND > Priority only allows
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
NOTIFICATION_ZEN_MODE_PRIORITY = 141;
+
+ // OPEN: Settings > Sound & notification > DND > Automatic rules
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
NOTIFICATION_ZEN_MODE_AUTOMATION = 142;
+
+ // OPEN: Settings > Apps > Configure apps > App links
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
MANAGE_DOMAIN_URLS = 143;
+
+ // OPEN: Settings > Sound & notification > DND > [Time based rule]
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
+
+ // OPEN: Settings > Sound & notification > DND > [External rule]
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
NOTIFICATION_ZEN_MODE_EXTERNAL_RULE = 145;
+
+ // OPEN: Settings > Sound & notification > DND > [Event rule]
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
NOTIFICATION_ZEN_MODE_EVENT_RULE = 146;
+
+ // ACTION: App notification settings > Block Notifications
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_BAN_APP_NOTES = 147;
+
+ // ACTION: Notification shade > Dismiss all button
+ // CATEGORY: NOTIFICATION
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_DISMISS_ALL_NOTES = 148;
+
+ // OPEN: QS Do Not Disturb detail panel
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
QS_DND_DETAILS = 149;
+
+ // OPEN: QS Bluetooth detail panel
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
QS_BLUETOOTH_DETAILS = 150;
+
+ // OPEN: QS Cast detail panel
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
QS_CAST_DETAILS = 151;
+
+ // OPEN: QS Wi-Fi detail panel
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
QS_WIFI_DETAILS = 152;
+
+ // ACTION: QS Wi-Fi detail panel > Wi-Fi toggle
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
QS_WIFI_TOGGLE = 153;
+
+ // ACTION: QS Bluetooth detail panel > Bluetooth toggle
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
QS_BLUETOOTH_TOGGLE = 154;
+
+ // ACTION: QS Cellular detail panel > Cellular toggle
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
QS_CELLULAR_TOGGLE = 155;
+
+ // ACTION: QS User list panel > Select different user
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
QS_SWITCH_USER = 156;
+
+ // ACTION: QS Cast detail panel > Select cast device
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
QS_CAST_SELECT = 157;
+
+ // ACTION: QS Cast detail panel > Disconnect cast device
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
QS_CAST_DISCONNECT = 158;
+
+ // ACTION: Settings > Bluetooth > Toggle
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_BLUETOOTH_TOGGLE = 159;
+
+ // ACTION: Settings > Bluetooth > Overflow > Refresh
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_BLUETOOTH_SCAN = 160;
+
+ // ACTION: Settings > Bluetooth > Overflow > Rename this device
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_BLUETOOTH_RENAME = 161;
+
+ // ACTION: Settings > Bluetooth > Overflow > Show received files
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_BLUETOOTH_FILES = 162;
+
+ // ACTION: QS DND details panel > Increase / Decrease exit time
+ // SUBTYPE: true is increase, false is decrease
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
QS_DND_TIME = 163;
+
+ // ACTION: QS DND details panel > [Exit condition]
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
QS_DND_CONDITION_SELECT = 164;
+
+ // ACTION: QS DND details panel > [DND mode]
+ // SUBTYPE: 1 is priority, 2 is silence, 3 is alarms only
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
QS_DND_ZEN_SELECT = 165;
+
+ // ACTION: QS DND detail panel > DND toggle
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
QS_DND_TOGGLE = 166;
+
+ // ACTION: DND Settings > Priority only allows > Reminder toggle
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_ZEN_ALLOW_REMINDERS = 167;
+
+ // ACTION: DND Settings > Priority only allows > Event toggle
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_ZEN_ALLOW_EVENTS = 168;
+
+ // ACTION: DND Settings > Priority only allows > Messages
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_ZEN_ALLOW_MESSAGES = 169;
+
+ // ACTION: DND Settings > Priority only allows > Calls
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_ZEN_ALLOW_CALLS = 170;
+
+ // ACTION: DND Settings > Priority only allows > Repeat callers toggle
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_ZEN_ALLOW_REPEAT_CALLS = 171;
+
+ // ACTION: DND Settings > Automatic rules > Add rule
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_ZEN_ADD_RULE = 172;
+
+ // ACTION: DND Settings > Automatic rules > Add rule > OK
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_ZEN_ADD_RULE_OK = 173;
+
+ // ACTION: DND Settings > Automatic rules > [Rule] > Delete rule
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_ZEN_DELETE_RULE = 174;
+
+ // ACTION: DND Settings > Automatic rules > [Rule] > Delete rule > Delete
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_ZEN_DELETE_RULE_OK = 175;
+
+ // ACTION: DND Settings > Automatic rules > [Rule] > Toggle
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_ZEN_ENABLE_RULE = 176;
+
+ // ACTION: Settings > More > Airplane mode toggle
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_AIRPLANE_TOGGLE = 177;
+
+ // ACTION: Settings > Data usage > Cellular data toggle
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_CELL_DATA_TOGGLE = 178;
+
+ // OPEN: Settings > Sound & notification > Notification access
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
NOTIFICATION_ACCESS = 179;
+
+ // OPEN: Settings > Sound & notification > Do Not Disturb access
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
NOTIFICATION_ZEN_MODE_ACCESS = 180;
+
+ // OPEN: Settings > Apps > Configure apps > Default Apps
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
APPLICATIONS_DEFAULT_APPS = 181;
+
+ // OPEN: Settings > Internal storage > Apps storage
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
APPLICATIONS_STORAGE_APPS = 182;
+
+ // OPEN: Settings > Security > Usage access
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
APPLICATIONS_USAGE_ACCESS_DETAIL = 183;
+
+ // OPEN: Settings > Battery > Battery optimization
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
APPLICATIONS_HIGH_POWER_APPS = 184;
+
+ // OBSOLETE
FUELGAUGE_HIGH_POWER_DETAILS = 185;
+
+ // ACTION: Lockscreen > Unlock gesture
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 5.1.1
+ // GMS: 7.8.22
ACTION_LS_UNLOCK = 186;
+
+ // ACTION: Lockscreen > Pull shade open
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 5.1.1
+ // GMS: 7.8.22
ACTION_LS_SHADE = 187;
+
+ // ACTION: Lockscreen > Tap on lock, shows hint
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 5.1.1
+ // GMS: 7.8.22
ACTION_LS_HINT = 188;
+
+ // ACTION: Lockscreen > Camera
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 5.1.1
+ // GMS: 7.8.22
ACTION_LS_CAMERA = 189;
+
+ // ACTION: Lockscreen > Dialer
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 5.1.1
+ // GMS: 7.8.22
ACTION_LS_DIALER = 190;
+
+ // ACTION: Lockscreen > Tap on lock, locks phone
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 5.1.1
+ // GMS: 7.8.22
ACTION_LS_LOCK = 191;
+
+ // ACTION: Lockscreen > Tap on notification, false touch rejection
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 5.1.1
+ // GMS: 7.8.22
ACTION_LS_NOTE = 192;
+
+ // ACTION: Lockscreen > Swipe down to open quick settings
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.8.22
ACTION_LS_QS = 193;
+
+ // ACTION: Swipe down to open quick settings when unlocked
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.8.22
ACTION_SHADE_QS_PULL = 194;
+
+ // ACTION: Notification shade > Tap to open quick settings
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.8.22
ACTION_SHADE_QS_TAP = 195;
+
+ // OPEN: Lockscreen
+ // SUBTYPE: 0 is unsecure, 1 is secured by password / pattern / PIN
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 5.1.1
+ // GMS: 7.8.22
LOCKSCREEN = 196;
+
+ // OPEN: Lockscreen > Screen to enter password / pattern / PIN
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 5.1.1
+ // GMS: 7.8.22
BOUNCER = 197;
+
+ // OPEN: Screen turned on
+ // SUBTYPE: 2 is user action
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 5.1.1
+ // GMS: 7.8.22
SCREEN = 198;
+
+ // OPEN: Notification caused sound, vibration, and/or LED blink
+ // SUBTYPE: 1 is buzz, 2 is beep, blink is 4, or'd together
+ // CATEGORY: NOTIFICATION
+ // OS: 5.1.1
+ // GMS: 7.8.53
NOTIFICATION_ALERT = 199;
+
+ // ACTION: Lockscreen > Emergency Call button
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 5.1.1
+ // GMS: 7.5.26
ACTION_EMERGENCY_CALL = 200;
+
+ // OPEN: Settings > Apps > Configure > Default apps > Assist & voice input
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
APPLICATIONS_MANAGE_ASSIST = 201;
+
+ // OPEN: Settings > Memory
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
PROCESS_STATS_SUMMARY = 202;
+
+ // ACTION: Settings > Display > When device is rotated
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_ROTATION_LOCK = 203;
+
+ // ACTION: Long press on notification to view controls
+ // CATEGORY: NOTIFICATION
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_NOTE_CONTROLS = 204;
+
+ // ACTION: Notificatoin controls > Info button
+ // CATEGORY: NOTIFICATION
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_NOTE_INFO = 205;
+
+ // ACTION: Notification controls > Settings button
+ // CATEGORY: NOTIFICATION
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_APP_NOTE_SETTINGS = 206;
+
+ // OPEN: Volume Dialog (with hardware buttons)
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.5.26
VOLUME_DIALOG = 207;
+
+ // OPEN: Volume dialog > Expanded volume dialog (multiple sliders)
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.5.26
VOLUME_DIALOG_DETAILS = 208;
+
+ // ACTION: Volume dialog > Adjust volume slider
+ // SUBTYPE: volume level (0-7)
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_VOLUME_SLIDER = 209;
+
+ // ACTION: Volume dialog > Select non-active stream
+ // SUBTYPE: stream (defined in AudioSystem.java)
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_VOLUME_STREAM = 210;
+
+ // ACTION: Adjust volume with hardware key
+ // SUBTYPE: volume level (0-7)
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_VOLUME_KEY = 211;
+
+ // ACTION: Volume dialog > Mute a stream by tapping icon
+ // SUBTYPE: mute is 1, audible is 2
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_VOLUME_ICON = 212;
+
+ // ACTION: Volume dialog > Change ringer mode by tapping icon
+ // SUBTYPE: 2 is audible, 3 is vibrate
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_RINGER_MODE = 213;
+
+ // ACTION: Chooser shown (share target, file open, etc.)
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_ACTIVITY_CHOOSER_SHOWN = 214;
+
+ // ACTION: Chooser > User taps an app target
+ // SUBTYPE: Index of target
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET = 215;
+
+ // ACTION: Chooser > User taps a service target
+ // SUBTYPE: Index of target
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET = 216;
+
+ // ACTION: Chooser > User taps a standard target
+ // SUBTYPE: Index of target
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET = 217;
+
+ // ACTION: QS Brightness Slider (with auto brightness disabled)
+ // SUBTYPE: slider value
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_BRIGHTNESS = 218;
+
+ // ACTION: QS Brightness Slider (with auto brightness enabled)
+ // SUBTYPE: slider value
+ // CATEGORY: QUICK_SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_BRIGHTNESS_AUTO = 219;
+
+ // OPEN: Settings > Display > Brightness Slider
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
BRIGHTNESS_DIALOG = 220;
+
+ // OPEN: Settings > Apps > Configure Apps > Draw over other apps
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
SYSTEM_ALERT_WINDOW_APPS = 221;
+
+ // OPEN: Display has entered dream mode
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.5.26
DREAMING = 222;
+
+ // OPEN: Display has entered ambient notification mode
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.5.26
DOZING = 223;
+
+ // OPEN: Overview
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.5.26
OVERVIEW_ACTIVITY = 224;
+
+ // OPEN: Settings > About phone > Legal information
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ABOUT_LEGAL_SETTINGS = 225;
+
+ // OPEN: Settings > Search > Perform search
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_SEARCH_RESULTS = 226;
+
+ // OPEN: Settings > System UI Tuner
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
TUNER = 227;
+
+ // OPEN: Settings > System UI Tuner > Quick Settings
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
TUNER_QS = 228;
+
+ // OPEN: Settings > System UI Tuner > Demo mode
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
TUNER_DEMO_MODE = 229;
+
+ // ACTION: Settings > System UI Tuner > Quick Settings > Move tile
+ // PACKAGE: Tile
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
TUNER_QS_REORDER = 230;
+
+ // ACTION: Settings > System UI Tuner > Quick Settings > Add tile
+ // PACKAGE: Tile
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
TUNER_QS_ADD = 231;
+
+ // ACTION: Settings > System UI Tuner > Quick Settings > Remove tile
+ // PACKAGE: Tile
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
TUNER_QS_REMOVE = 232;
+
+ // ACTION: Settings > System UI Tuner > Status bar > Enable icon
+ // PACKAGE: Icon
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
TUNER_STATUS_BAR_ENABLE = 233;
+
+ // ACTION: Settings > System UI Tuner > Status bar > Disable icon
+ // PACKAGE: Icon
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
TUNER_STATUS_BAR_DISABLE = 234;
+
+ // ACTION: Settings > System UI Tuner > Demo mode > Enable demo mode
+ // SUBTYPE: false is disabled, true is enabled
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
TUNER_DEMO_MODE_ENABLED = 235;
+
+ // ACTION: Settings > System UI Tuner > Demo mode > Show demo mode
+ // SUBTYPE: false is disabled, true is enabled
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
TUNER_DEMO_MODE_ON = 236;
+
+ // ACTION: Settings > System UI Tuner > Show embedded battery percentage
+ // SUBTYPE: 0 is disabled, 1 is enabled
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
TUNER_BATTERY_PERCENTAGE = 237;
+
+ // OPEN: Settings > Developer options > Inactive apps
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.5.26
FUELGAUGE_INACTIVE_APPS = 238;
+
+ // ACTION: Long press home to bring up assistant
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.5.26
ACTION_ASSIST_LONG_PRESS = 239;
+
+ // OPEN: Settings > Security > Nexus Imprint > Add Fingerprint
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.8.99
FINGERPRINT_ENROLLING = 240;
+
+ // OPEN: Fingerprint Enroll > Find Sensor
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.8.99
FINGERPRINT_FIND_SENSOR = 241;
+
+ // OPEN: Fingerprint Enroll > Fingerprint Enrolled!
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.8.99
FINGERPRINT_ENROLL_FINISH = 242;
+
+ // OPEN: Fingerprint Enroll introduction
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.8.99
FINGERPRINT_ENROLL_INTRO = 243;
+
+ // OPEN: Fingerprint Enroll onboarding
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.8.99
FINGERPRINT_ENROLL_ONBOARD = 244;
+
+ // OPEN: Fingerprint Enroll > Let's Start!
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.8.99
FINGERPRINT_ENROLL_SIDECAR = 245;
+
+ // OPEN: Fingerprint Enroll SUW > Let's Start!
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.8.99
FINGERPRINT_ENROLLING_SETUP = 246;
+
+ // OPEN: Fingerprint Enroll SUW > Find Sensor
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.8.99
FINGERPRINT_FIND_SENSOR_SETUP = 247;
+
+ // OPEN: Fingerprint Enroll SUW > Fingerprint Enrolled!
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.8.99
FINGERPRINT_ENROLL_FINISH_SETUP = 248;
+
+ // OPEN: Fingerprint Enroll SUW introduction
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.8.99
FINGERPRINT_ENROLL_INTRO_SETUP = 249;
+
+ // OPEN: Fingerprint Enroll SUW onboarding
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.8.99
FINGERPRINT_ENROLL_ONBOARD_SETUP = 250;
+
+ // ACTION: Add fingerprint > Enroll fingerprint
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.8.99
ACTION_FINGERPRINT_ENROLL = 251;
+
+ // ACTION: Authenticate using fingerprint
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.8.99
ACTION_FINGERPRINT_AUTH = 252;
+
+ // ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Delete
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.8.99
ACTION_FINGERPRINT_DELETE = 253;
+
+ // ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Rename
+ // CATEGORY: SETTINGS
+ // OS: 6.0
+ // GMS: 7.8.99
ACTION_FINGERPRINT_RENAME = 254;
+
+ // ACTION: Double tap camera shortcut
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.8.99
ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE = 255;
+
+ // ACTION: Double twist camera shortcut
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: 6.0
+ // GMS: 7.8.99
ACTION_WIGGLE_CAMERA_GESTURE = 256;
+
+ // OPEN: QS Work Mode tile shown
+ // ACTION: QS Work Mode tile tapped
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: N
+ // GMS: 7.8.99
QS_WORKMODE = 257;
+
+ // OPEN: Settings > Developer Options > Background Check
+ // CATEGORY: SETTINGS
+ // OS: N
+ // GMS: 7.8.99
BACKGROUND_CHECK_SUMMARY = 258;
+
+ // OPEN: QS Lock tile shown
+ // ACTION: QS Lock tile tapped
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: N
+ // GMS: 7.8.99
QS_LOCK_TILE = 259;
+
+ // OPEN: QS User Tile shown
+ // CATEGORY: QUICK_SETTINGS
+ // OS: N
+ // GMS: 7.8.99
QS_USER_TILE = 260;
+
+ // OPEN: QS Battery tile shown
+ // CATEGORY: QUICK_SETTINGS
+ // OS: N
+ // GMS: 7.8.99
QS_BATTERY_TILE = 261;
+
+ // OPEN: Settings > Sound > Do not disturb > Visual interruptions
+ // CATEGORY: SETTINGS
+ // OS: N
+ // GMS: 7.8.99
NOTIFICATION_ZEN_MODE_VISUAL_INTERRUPTIONS = 262;
+
+ // ACTION: Visual interruptions > No screen interuptions toggle
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: SETTINGS
+ // OS: N
+ // GMS: 7.8.99
ACTION_ZEN_ALLOW_WHEN_SCREEN_OFF = 263;
- // Dead
+
+ // ACTION: Visual interruptions > No notification light toggle
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: SETTINGS
+ // OS: N
+ // GMS: 7.8.99
ACTION_ZEN_ALLOW_LIGHTS = 264;
+
+ // OPEN: Settings > Notifications > [App] > Topic Notifications
+ // CATEGORY: SETTINGS
+ // OS: N
+ // GMS: 7.8.99
NOTIFICATION_TOPIC_NOTIFICATION = 265;
+
+ // ACTION: Settings > Apps > Default Apps > Select different SMS app
+ // PACKAGE: Selected SMS app
+ // CATEGORY: SETTINGS
+ // OS: N
+ // GMS: 7.8.99
ACTION_DEFAULT_SMS_APP_CHANGED = 266;
+
+ // OPEN: QS Color modification tile shown
+ // ACTION: QS Color modification tile tapped
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: N
+ // GMS: 7.8.99
QS_COLOR_MATRIX = 267;
+
+ // OPEN: QS Custom tile shown
+ // ACTION: QS Work Mode tile tapped
+ // CATEGORY: QUICK_SETTINGS
+ // OS: N
+ // GMS: 7.8.99
QS_CUSTOM = 268;
+
+ // ACTION: Visual interruptions > Never turn off the screen toggle
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: SETTINGS
+ // OS: N
+ // GMS: 7.8.99
ACTION_ZEN_ALLOW_WHEN_SCREEN_ON = 269;
- // Logged when the user docks a window from recents by
- // longpressing a task and dragging it to the dock area.
+ // ACTION: Overview > Long-press task, drag to enter split-screen
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
ACTION_WINDOW_DOCK_DRAG_DROP = 270;
- // Logged when the user docks a fullscreen window by long pressing
- // recents which also opens recents on the lower/right side.
+ // ACTION: In App > Long-press Overview button to enter split-screen
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
ACTION_WINDOW_DOCK_LONGPRESS = 271;
- // Logged when the user docks a window by dragging from the navbar
- // which also opens recents on the lower/right side.
+ // ACTION: In App > Swipe Overview button to enter split-screen
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
ACTION_WINDOW_DOCK_SWIPE = 272;
- // Logged when the user launches a profile-specific app and we
- // intercept it with the confirm credentials UI.
+ // ACTION: Launch profile-specific app > Confirm credentials
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
PROFILE_CHALLENGE = 273;
+ // OPEN: QS Battery detail panel
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
QS_BATTERY_DETAIL = 274;
- // Logged when the user goes into the overview history.
+ // OPEN: Overview > History
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
OVERVIEW_HISTORY = 275;
- // Logged when the user pages through overview.
- OVERVIEW_PAGE = 276;
+ // ACTION: Overview > Page by tapping Overview button
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
+ ACTION_OVERVIEW_PAGE = 276;
- // Logged when the user launches a task from overview.
- OVERVIEW_SELECT = 277;
+ // ACTION: Overview > Select app
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
+ ACTION_OVERVIEW_SELECT = 277;
- // Logged when the user views the emergency info.
+ // ACTION: View emergency info
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
ACTION_VIEW_EMERGENCY_INFO = 278;
- // Logged when the user views the edit emergency info activity.
+ // ACTION: Edit emergency info activity
+ // CATEGORY: SETTINGS
+ // OS: N
+ // GMS: 7.8.99
ACTION_EDIT_EMERGENCY_INFO = 279;
- // Logged when the user edits an emergency info field.
+ // ACTION: Edit emergency info field
+ // CATEGORY: SETTINGS
+ // OS: N
+ // GMS: 7.8.99
ACTION_EDIT_EMERGENCY_INFO_FIELD = 280;
- // Logged when the user adds a new emergency contact.
+ // ACTION: Add emergency contact
+ // CATEGORY: SETTINGS
+ // OS: N
+ // GMS: 7.8.99
ACTION_ADD_EMERGENCY_CONTACT = 281;
- // Logged when the user deletes an emergency contact.
+ // ACTION: Delete emergency contact
+ // CATEGORY: SETTINGS
+ // OS: N
+ // GMS: 7.8.99
ACTION_DELETE_EMERGENCY_CONTACT = 282;
- // Logged when the user calls an emergency contact.
+ // ACTION: Call emergency contact
+ // CATEGORY: SETTINGS
+ // OS: N
+ // GMS: 7.8.99
ACTION_CALL_EMERGENCY_CONTACT = 283;
- // QS Tile for Data Saver.
+ // OPEN: QS Data Saver tile shown
+ // ACTION: QS Data Saver tile tapped
+ // CATEGORY: QUICK_SETTINGS
QS_DATA_SAVER = 284;
// OPEN: Settings > Security > User credentials
// CATEGORY: Settings
- // OS: 6.1
+ // OS: N
// GMS: 7.8.99
USER_CREDENTIALS = 285;
- // Logged when the user undocks a previously docked window by long pressing recents while in
- // docked mode.
+ // ACTION: In App (splitscreen) > Long-press Overview to exit split-screen
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
ACTION_WINDOW_UNDOCK_LONGPRESS = 286;
// Logged when the user scrolls through overview manually
@@ -370,43 +1770,84 @@
// indicate the user lowered the importance; positive means they increased it.
ACTION_SAVE_IMPORTANCE = 291;
- // Interactive bug report initiated from power menu.
+ // ACTION: Long-press power button, then tap "Take bug report" option.
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE = 292;
- // Full bug report initiated from power menu.
+ // ACTION: Long-press power button, then long-press "Take bug report" option.
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N
+ // GMS: 7.8.99
ACTION_BUGREPORT_FROM_POWER_MENU_FULL = 293;
+ // ACTION: Settings -> Developer Options -> Take bug report -> Interactive report
+ // CATEGORY: SETTINGS
+ // OS: N
+ // GMS: 7.8.99
// Interactive bug report initiated from Settings.
ACTION_BUGREPORT_FROM_SETTINGS_INTERACTIVE = 294;
- // Full bug report initiated from Settings.
+ // ACTION: Settings -> Developer Options -> Take bug report -> Full report
+ // CATEGORY: SETTINGS
+ // OS: N
+ // GMS: 7.8.99
+ // Interactive bug report initiated from Settings.
ACTION_BUGREPORT_FROM_SETTINGS_FULL = 295;
- // Bug report canceled using system notification.
+ // ACTION: User tapped notification action to cancel a bug report
+ // CATEGORY: NOTIFICATION
+ // OS: N
+ // GMS: 7.8.99
ACTION_BUGREPORT_NOTIFICATION_ACTION_CANCEL = 296;
- // Bug report details screen open using system notification.
+ // 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;
- // Additional Bug report screen shot taken using system notification.
+ // 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;
- // Bug report shared by user using system notification.
+ // ACTION: User tapped notification to share bug report
+ // CATEGORY: NOTIFICATION
+ // OS: N
+ // GMS: 7.8.99
ACTION_BUGREPORT_NOTIFICATION_ACTION_SHARE = 299;
- // User changed bug report name using the details screen.
+ // 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;
- // User changed bug report title using the details screen.
+ // 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;
- // User changed bug report description using the details screen.
+ // 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;
- // Changes made on bug report details screen were saved by user.
+ // 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;
- // Changes made on bug report details screen were canceled by user.
+ // 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.
@@ -504,8 +1945,18 @@
// 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;
+
+ // Logs that the user has edited the enabled VR listeners.
+ VR_MANAGE_LISTENERS = 334;
+
// 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/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index f537d18..3659a40 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -16,9 +16,14 @@
package com.android.server.appwidget;
+import static android.content.Context.KEYGUARD_SERVICE;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DevicePolicyManagerInternal.OnCrossProfileWidgetProvidersChangeListener;
@@ -72,10 +77,12 @@
import android.util.TypedValue;
import android.util.Xml;
import android.view.Display;
+import android.view.View;
import android.view.WindowManager;
import android.widget.RemoteViews;
import com.android.internal.R;
+import com.android.internal.app.UnlaunchableAppActivity;
import com.android.internal.appwidget.IAppWidgetHost;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.os.BackgroundThread;
@@ -146,7 +153,7 @@
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
if (DEBUG) {
- Slog.i(TAG, "Received broadcast: " + action);
+ Slog.i(TAG, "Received broadcast: " + action + " on user " + userId);
}
if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
@@ -156,10 +163,10 @@
} else if (Intent.ACTION_USER_STOPPED.equals(action)) {
onUserStopped(userId);
} else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- reloadWidgetsMaskedStateForUser(userId);
+ reloadWidgetsMaskedStateForGroup(userId);
} else if (Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED.equals(action)) {
synchronized (mLock) {
- reloadWidgetProfileUnavailableMaskedStateLocked(userId);
+ reloadWidgetsMaskedState(userId);
}
} else if (Intent.ACTION_PACKAGES_SUSPENDED.equals(action)) {
String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
@@ -202,6 +209,7 @@
private final AlarmManager mAlarmManager;
private final UserManager mUserManager;
private final AppOpsManager mAppOpsManager;
+ private final KeyguardManager mKeyguardManager;
private final SecurityPolicy mSecurityPolicy;
@@ -223,6 +231,7 @@
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ mKeyguardManager = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
mSaveStateHandler = BackgroundThread.getHandler();
mCallbackHandler = new CallbackHandler(mContext.getMainLooper());
mBackupRestoreController = new BackupRestoreController();
@@ -436,48 +445,51 @@
/**
* Reload all widgets' masked state for the given user and its associated profiles, including
* due to user not being available and package suspension.
+ * userId must be the group parent.
*/
- private void reloadWidgetsMaskedStateForUser(int userId) {
- if (!mUserManager.isUserUnlocked(userId) ||
- isProfileWithLockedParent(userId)) {
+ private void reloadWidgetsMaskedStateForGroup(int userId) {
+ if (!mUserManager.isUserUnlocked(userId)) {
return;
}
synchronized (mLock) {
- reloadWidgetPackageSuspensionMaskedStateLocked(userId);
+ reloadWidgetsMaskedState(userId);
List<UserInfo> profiles = mUserManager.getEnabledProfiles(userId);
if (profiles != null) {
for (int i = 0; i < profiles.size(); i++) {
UserInfo user = profiles.get(i);
- reloadWidgetProfileUnavailableMaskedStateLocked(user.id);
- reloadWidgetPackageSuspensionMaskedStateLocked(user.id);
+ reloadWidgetsMaskedState(user.id);
}
}
}
}
- /**
- * Mask/unmask widgets in the given profile, depending on the quiet state
- * or locked state of the profile.
- */
- private void reloadWidgetProfileUnavailableMaskedStateLocked(int profileId) {
+ private void reloadWidgetsMaskedState(int userId) {
final long identity = Binder.clearCallingIdentity();
try {
- if (!isProfileWithUnlockedParent(profileId)) {
- return;
- }
- UserInfo user = mUserManager.getUserInfo(profileId);
- boolean shouldMask = user.isQuietModeEnabled() ||
- !mUserManager.isUserUnlocked(user.getUserHandle());
+ UserInfo user = mUserManager.getUserInfo(userId);
+
+ boolean lockedProfile = !mUserManager.isUserUnlocked(userId);
+ boolean quietProfile = user.isQuietModeEnabled();
final int N = mProviders.size();
for (int i = 0; i < N; i++) {
Provider provider = mProviders.get(i);
int providerUserId = provider.getUserId();
- if (providerUserId != profileId) {
+ if (providerUserId != userId) {
continue;
}
- if (provider.setMaskedByProfileUnavailabledLocked(shouldMask)) {
+
+ boolean changed = provider.setMaskedByLockedProfileLocked(lockedProfile);
+ changed |= provider.setMaskedByQuietProfileLocked(quietProfile);
+ try {
+ boolean suspended = mPackageManager.isPackageSuspendedForUser(
+ provider.info.provider.getPackageName(), provider.getUserId());
+ changed |= provider.setMaskedBySuspendedPackageLocked(suspended);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to query application info", e);
+ }
+ if (changed) {
if (provider.isMaskedLocked()) {
- maskWidgetsViewsLocked(provider);
+ maskWidgetsViewsLocked(provider, null);
} else {
unmaskWidgetsViewsLocked(provider);
}
@@ -489,33 +501,6 @@
}
/**
- * Reload widget's masked state due to package suspension state.
- */
- private void reloadWidgetPackageSuspensionMaskedStateLocked(int profileId) {
- final int N = mProviders.size();
- for (int i = 0; i < N; i++) {
- Provider provider = mProviders.get(i);
- int providerUserId = provider.getUserId();
- if (providerUserId != profileId) {
- continue;
- }
- try {
- boolean suspended = mPackageManager.isPackageSuspendedForUser(
- provider.info.provider.getPackageName(), provider.getUserId());
- if (provider.setMaskedBySuspendedPackageLocked(suspended)) {
- if (provider.isMaskedLocked()) {
- maskWidgetsViewsLocked(provider);
- } else {
- unmaskWidgetsViewsLocked(provider);
- }
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to query application info", e);
- }
- }
- }
-
- /**
* Incrementally update the masked state due to package suspension state.
*/
private void updateWidgetPackageSuspensionMaskedState(String[] packagesArray, boolean suspended,
@@ -535,7 +520,7 @@
}
if (provider.setMaskedBySuspendedPackageLocked(suspended)) {
if (provider.isMaskedLocked()) {
- maskWidgetsViewsLocked(provider);
+ maskWidgetsViewsLocked(provider, null);
} else {
unmaskWidgetsViewsLocked(provider);
}
@@ -544,14 +529,13 @@
}
}
- private Bitmap createMaskedWidgetBitmap(Provider provider) {
+ private Bitmap createMaskedWidgetBitmap(String providerPackage, int providerUserId) {
final long identity = Binder.clearCallingIdentity();
try {
// Load the unbadged application icon and pass it to the widget to appear on
// the masked view.
- final String providerPackage = provider.info.provider.getPackageName();
Context userContext = mContext.createPackageContextAsUser(providerPackage, 0,
- UserHandle.of(provider.getUserId()));
+ UserHandle.of(providerUserId));
PackageManager pm = userContext.getPackageManager();
Drawable icon = pm.getApplicationInfo(providerPackage, 0).loadUnbadgedIcon(pm);
// Create a bitmap of the icon which is what the widget's remoteview requires.
@@ -566,18 +550,73 @@
}
}
- private void maskWidgetsViewsLocked(Provider provider) {
- Bitmap iconBitmap = createMaskedWidgetBitmap(provider);
+ private RemoteViews createMaskedWidgetRemoteViews(Bitmap icon, boolean showBadge,
+ PendingIntent onClickIntent) {
+ RemoteViews views = new RemoteViews(mContext.getPackageName(),
+ R.layout.work_widget_mask_view);
+ if (icon != null) {
+ views.setImageViewBitmap(R.id.work_widget_app_icon, icon);
+ }
+ if (!showBadge) {
+ views.setViewVisibility(R.id.work_widget_badge_icon, View.INVISIBLE);
+ }
+ if (onClickIntent != null) {
+ views.setOnClickPendingIntent(R.id.work_widget_mask_frame, onClickIntent);
+ }
+ return views;
+ }
+
+ /**
+ * Mask the target widget belonging to the specified provider, or all active widgets
+ * of the provider if target widget == null.
+ */
+ private void maskWidgetsViewsLocked(Provider provider, Widget targetWidget) {
+ final int widgetCount = provider.widgets.size();
+ if (widgetCount == 0) {
+ return;
+ }
+ final String providerPackage = provider.info.provider.getPackageName();
+ final int providerUserId = provider.getUserId();
+ Bitmap iconBitmap = createMaskedWidgetBitmap(providerPackage, providerUserId);
if (iconBitmap == null) {
return;
}
+ final boolean showBadge;
+ final Intent onClickIntent;
+ if (provider.maskedBySuspendedPackage) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ UserInfo userInfo = mUserManager.getUserInfo(providerUserId);
+ showBadge = userInfo.isManagedProfile();
+ onClickIntent = UnlaunchableAppActivity.createPackageSuspendedDialogIntent(
+ providerPackage, providerUserId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ } else if (provider.maskedByQuietProfile) {
+ showBadge = true;
+ onClickIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(
+ providerUserId);
+ } else /* provider.maskedByLockedProfile */ {
+ showBadge = true;
+ onClickIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null,
+ providerUserId);
+ if (onClickIntent != null) {
+ onClickIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ }
+ }
- final int widgetCount = provider.widgets.size();
for (int j = 0; j < widgetCount; j++) {
Widget widget = provider.widgets.get(j);
- if (widget.replaceWithMaskedViewsLocked(mContext, iconBitmap)) {
- scheduleNotifyUpdateAppWidgetLocked(widget,
- widget.getEffectiveViewsLocked());
+ if (targetWidget != null && targetWidget != widget) continue;
+ PendingIntent intent = null;
+ if (onClickIntent != null) {
+ intent = PendingIntent.getActivity(mContext, widget.appWidgetId,
+ onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+ RemoteViews views = createMaskedWidgetRemoteViews(iconBitmap, showBadge, intent);
+ if (widget.replaceWithMaskedViewsLocked(views)) {
+ scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
}
}
}
@@ -587,8 +626,7 @@
for (int j = 0; j < widgetCount; j++) {
Widget widget = provider.widgets.get(j);
if (widget.clearMaskedViewsLocked()) {
- scheduleNotifyUpdateAppWidgetLocked(widget,
- widget.getEffectiveViewsLocked());
+ scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
}
}
}
@@ -2458,7 +2496,7 @@
return mPackageManager.queryIntentReceivers(intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- flags, userId);
+ flags, userId).getList();
} catch (RemoteException re) {
return Collections.emptyList();
} finally {
@@ -2472,7 +2510,7 @@
}
synchronized (mLock) {
ensureGroupStateLoadedLocked(userId);
- reloadWidgetsMaskedStateForUser(userId);
+ reloadWidgetsMaskedStateForGroup(mSecurityPolicy.getGroupParent(userId));
final int N = mProviders.size();
for (int i = 0; i < N; i++) {
@@ -2614,10 +2652,7 @@
// If we are adding a widget it might be for a provider that
// is currently masked, if so mask the widget.
if (widget.provider.isMaskedLocked()) {
- Bitmap bitmap = createMaskedWidgetBitmap(widget.provider);
- if (bitmap != null) {
- widget.replaceWithMaskedViewsLocked(mContext, bitmap);
- }
+ maskWidgetsViewsLocked(widget.provider, widget);
} else {
widget.clearMaskedViewsLocked();
}
@@ -3014,7 +3049,6 @@
private void onUserStopped(int userId) {
synchronized (mLock) {
- boolean providersChanged = false;
boolean crossProfileWidgetsChanged = false;
// Remove widgets that have both host and provider in the user.
@@ -3050,16 +3084,8 @@
}
}
- // Remove the providers and notify hosts in other profiles.
- final int providerCount = mProviders.size();
- for (int i = providerCount - 1; i >= 0; i--) {
- Provider provider = mProviders.get(i);
- if (provider.getUserId() == userId) {
- crossProfileWidgetsChanged |= !provider.widgets.isEmpty();
- providersChanged = true;
- deleteProviderLocked(provider);
- }
- }
+ // Leave the providers present as hosts will show the widgets
+ // masked while the user is stopped.
// Remove grants for this user.
final int grantCount = mPackagesWithBindWidgetPermission.size();
@@ -3082,11 +3108,6 @@
mNextAppWidgetIds.removeAt(nextIdIndex);
}
- // Announce removed provider changes to all hosts in the group.
- if (providersChanged) {
- scheduleNotifyGroupHostsForProvidersChangedLocked(userId);
- }
-
// Save state if removing a profile changed the group state.
// Nothing will be saved if the group parent was removed.
if (crossProfileWidgetsChanged) {
@@ -3624,7 +3645,8 @@
PendingIntent broadcast;
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
- boolean maskedByProfileUnavailable;
+ boolean maskedByLockedProfile;
+ boolean maskedByQuietProfile;
boolean maskedBySuspendedPackage;
int tag = TAG_UNDEFINED; // for use while saving state (the index)
@@ -3656,22 +3678,29 @@
return "Provider{" + id + (zombie ? " Z" : "") + '}';
}
- // returns true if the provider's masked state is changed as a result
- public boolean setMaskedByProfileUnavailabledLocked(boolean masked) {
- boolean oldMaskedState = isMaskedLocked();
- maskedByProfileUnavailable = masked;
- return isMaskedLocked() != oldMaskedState;
+ // returns true if it's different from previous state.
+ public boolean setMaskedByQuietProfileLocked(boolean masked) {
+ boolean oldState = maskedByQuietProfile;
+ maskedByQuietProfile = masked;
+ return masked != oldState;
}
- // returns true if the provider's masked state is changed as a result
+ // returns true if it's different from previous state.
+ public boolean setMaskedByLockedProfileLocked(boolean masked) {
+ boolean oldState = maskedByLockedProfile;
+ maskedByLockedProfile = masked;
+ return masked != oldState;
+ }
+
+ // returns true if it's different from previous state.
public boolean setMaskedBySuspendedPackageLocked(boolean masked) {
- boolean oldMaskedState = isMaskedLocked();
+ boolean oldState = maskedBySuspendedPackage;
maskedBySuspendedPackage = masked;
- return isMaskedLocked() != oldMaskedState;
+ return masked != oldState;
}
public boolean isMaskedLocked() {
- return maskedByProfileUnavailable || maskedBySuspendedPackage;
+ return maskedByQuietProfile || maskedByLockedProfile || maskedBySuspendedPackage;
}
}
@@ -3828,14 +3857,8 @@
return "AppWidgetId{" + appWidgetId + ':' + host + ':' + provider + '}';
}
- private boolean replaceWithMaskedViewsLocked(Context context, Bitmap icon) {
- if (maskedViews != null) {
- return false;
- }
- maskedViews = new RemoteViews(context.getPackageName(), R.layout.work_widget_mask_view);
- if (icon != null) {
- maskedViews.setImageViewBitmap(R.id.work_widget_app_icon, icon);
- }
+ private boolean replaceWithMaskedViewsLocked(RemoteViews views) {
+ maskedViews = views;
return true;
}
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/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 8cfeb74..e241a4a 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -19,7 +19,6 @@
import android.Manifest;
import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothCallback;
@@ -44,7 +43,6 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
-import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -53,10 +51,9 @@
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
-import android.util.Log;
+import android.util.Slog;
import java.io.FileDescriptor;
-import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
@@ -92,14 +89,15 @@
private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
- private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
- private static final int MESSAGE_TIMEOUT_BIND =100;
- private static final int MESSAGE_TIMEOUT_UNBIND =101;
+ private static final int MESSAGE_BLUETOOTH_STATE_CHANGE = 60;
+ private static final int MESSAGE_TIMEOUT_BIND = 100;
+ private static final int MESSAGE_TIMEOUT_UNBIND = 101;
private static final int MESSAGE_USER_SWITCHED = 300;
+ private static final int MESSAGE_USER_UNLOCKED = 301;
private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
- private static final int MAX_SAVE_RETRIES=3;
- private static final int MAX_ERROR_RESTART_RETRIES=6;
+ private static final int MAX_SAVE_RETRIES = 3;
+ private static final int MAX_ERROR_RESTART_RETRIES = 6;
// Bluetooth persisted setting is off
private static final int BLUETOOTH_OFF=0;
@@ -176,7 +174,7 @@
String action = intent.getAction();
if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
- if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
+ if (DBG) Slog.d(TAG, "Bluetooth Adapter name changed to " + newName);
if (newName != null) {
storeNameAndAddress(newName, null);
}
@@ -195,10 +193,10 @@
try {
st = mBluetooth.getState();
} catch (RemoteException e) {
- Log.e(TAG,"Unable to call getState", e);
+ Slog.e(TAG,"Unable to call getState", e);
}
}
- Log.d(TAG, "state" + st);
+ Slog.d(TAG, "state" + st);
if (isAirplaneModeOn()) {
// Clear registered LE apps to force shut-off
@@ -214,16 +212,16 @@
mEnableExternal = false;
}
} catch(RemoteException e) {
- Log.e(TAG,"Unable to call onBrEdrDown", e);
+ Slog.e(TAG,"Unable to call onBrEdrDown", e);
}
} else if (st == BluetoothAdapter.STATE_ON){
// disable without persisting the setting
- Log.d(TAG, "Calling disable");
+ Slog.d(TAG, "Calling disable");
sendDisableMsg();
}
} else if (mEnableExternal) {
// enable without persisting the setting
- Log.d(TAG, "Calling enable");
+ Slog.d(TAG, "Calling enable");
sendEnableMsg(mQuietEnableExternal);
}
}
@@ -267,7 +265,7 @@
PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
} catch (PackageManager.NameNotFoundException e) {
// Some platforms, such as wearables do not have a system ui.
- Log.w(TAG, "Unable to resolve SystemUI's UID.", e);
+ Slog.w(TAG, "Unable to resolve SystemUI's UID.", e);
}
mSystemUiUid = sysUiUid;
}
@@ -320,17 +318,17 @@
* in the local cache
*/
private void loadStoredNameAndAddress() {
- if (DBG) Log.d(TAG, "Loading stored name and address");
+ if (DBG) Slog.d(TAG, "Loading stored name and address");
if (mContext.getResources().getBoolean
(com.android.internal.R.bool.config_bluetooth_address_validation) &&
Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
// if the valid flag is not set, don't load the address and name
- if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
+ if (DBG) Slog.d(TAG, "invalid bluetooth name and address stored");
return;
}
mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
- if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
+ if (DBG) Slog.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
}
/**
@@ -343,14 +341,14 @@
if (name != null) {
Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
mName = name;
- if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
+ if (DBG) Slog.d(TAG,"Stored Bluetooth name: " +
Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
}
if (address != null) {
Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
mAddress=address;
- if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
+ if (DBG) Slog.d(TAG,"Stored Bluetoothaddress: " +
Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
}
@@ -361,7 +359,7 @@
public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
if (callback == null) {
- Log.w(TAG, "Callback is null in registerAdapter");
+ Slog.w(TAG, "Callback is null in registerAdapter");
return null;
}
Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
@@ -374,7 +372,7 @@
public void unregisterAdapter(IBluetoothManagerCallback callback) {
if (callback == null) {
- Log.w(TAG, "Callback is null in unregisterAdapter");
+ Slog.w(TAG, "Callback is null in unregisterAdapter");
return;
}
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
@@ -403,7 +401,7 @@
public boolean isEnabled() {
if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
(!checkIfCallerIsForegroundUser())) {
- Log.w(TAG,"isEnabled(): not allowed for non-active and non system user");
+ Slog.w(TAG,"isEnabled(): not allowed for non-active and non system user");
return false;
}
@@ -411,7 +409,7 @@
try {
return (mBluetooth != null && mBluetooth.isEnabled());
} catch (RemoteException e) {
- Log.e(TAG, "isEnabled()", e);
+ Slog.e(TAG, "isEnabled()", e);
}
}
return false;
@@ -419,17 +417,17 @@
class ClientDeathRecipient implements IBinder.DeathRecipient {
public void binderDied() {
- if (DBG) Log.d(TAG, "Binder is dead - unregister Ble App");
+ if (DBG) Slog.d(TAG, "Binder is dead - unregister Ble App");
if (mBleAppCount > 0) --mBleAppCount;
if (mBleAppCount == 0) {
- if (DBG) Log.d(TAG, "Disabling LE only mode after application crash");
+ if (DBG) Slog.d(TAG, "Disabling LE only mode after application crash");
try {
if (mBluetooth != null) {
mBluetooth.onBrEdrDown();
}
} catch(RemoteException e) {
- Log.e(TAG,"Unable to call onBrEdrDown", e);
+ Slog.e(TAG,"Unable to call onBrEdrDown", e);
}
}
}
@@ -459,7 +457,7 @@
try {
if (mBluetooth != null) mBluetooth.onBrEdrDown();
} catch (RemoteException e) {
- Log.e(TAG, "error when disabling bluetooth", e);
+ Slog.e(TAG, "error when disabling bluetooth", e);
}
}
}
@@ -474,11 +472,11 @@
private void disableBleScanMode() {
try {
if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
- if (DBG) Log.d(TAG, "Reseting the mEnable flag for clean disable");
+ if (DBG) Slog.d(TAG, "Reseting the mEnable flag for clean disable");
mEnable = false;
}
} catch (RemoteException e) {
- Log.e(TAG, "getState()", e);
+ Slog.e(TAG, "getState()", e);
}
}
@@ -496,7 +494,7 @@
synchronized (this) {
++mBleAppCount;
}
- if (DBG) Log.d(TAG, "Registered for death Notification");
+ if (DBG) Slog.d(TAG, "Registered for death Notification");
}
} else {
@@ -508,10 +506,10 @@
synchronized (this) {
if (mBleAppCount > 0) --mBleAppCount;
}
- if (DBG) Log.d(TAG, "Unregistered for death Notification");
+ if (DBG) Slog.d(TAG, "Unregistered for death Notification");
}
}
- if (DBG) Log.d(TAG, "Updated BleAppCount" + mBleAppCount);
+ if (DBG) Slog.d(TAG, "Updated BleAppCount" + mBleAppCount);
if (mBleAppCount == 0 && mEnable) {
disableBleScanMode();
}
@@ -528,7 +526,7 @@
/** @hide*/
public boolean isBleAppPresent() {
- if (DBG) Log.d(TAG, "isBleAppPresent() count: " + mBleAppCount);
+ if (DBG) Slog.d(TAG, "isBleAppPresent() count: " + mBleAppCount);
return (mBleAppCount > 0);
}
@@ -536,7 +534,7 @@
* Action taken when GattService is turned off
*/
private void onBluetoothGattServiceUp() {
- if (DBG) Log.d(TAG,"BluetoothGatt Service is Up");
+ if (DBG) Slog.d(TAG,"BluetoothGatt Service is Up");
try{
if (isBleAppPresent() == false && mBluetooth != null
&& mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
@@ -548,7 +546,7 @@
Binder.restoreCallingIdentity(callingIdentity);
}
} catch(RemoteException e) {
- Log.e(TAG,"Unable to call onServiceUp", e);
+ Slog.e(TAG,"Unable to call onServiceUp", e);
}
}
@@ -557,10 +555,10 @@
* and turn off all service and stack if no LE app needs it
*/
private void sendBrEdrDownCallback() {
- if (DBG) Log.d(TAG,"Calling sendBrEdrDownCallback callbacks");
+ if (DBG) Slog.d(TAG,"Calling sendBrEdrDownCallback callbacks");
if(mBluetooth == null) {
- Log.w(TAG, "Bluetooth handle is null");
+ Slog.w(TAG, "Bluetooth handle is null");
return;
}
@@ -568,14 +566,14 @@
try {
mBluetooth.onBrEdrDown();
} catch(RemoteException e) {
- Log.e(TAG, "Call to onBrEdrDown() failed.", e);
+ Slog.e(TAG, "Call to onBrEdrDown() failed.", e);
}
} else {
// Need to stay at BLE ON. Disconnect all Gatt connections
try{
mBluetoothGatt.unregAll();
} catch(RemoteException e) {
- Log.e(TAG, "Unable to disconnect all apps.", e);
+ Slog.e(TAG, "Unable to disconnect all apps.", e);
}
}
}
@@ -586,7 +584,7 @@
"Need BLUETOOTH ADMIN permission");
if (DBG) {
- Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
+ Slog.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
" mBinding = " + mBinding);
}
int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
@@ -606,14 +604,14 @@
public boolean enable() {
if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
(!checkIfCallerIsForegroundUser())) {
- Log.w(TAG,"enable(): not allowed for non-active and non system user");
+ Slog.w(TAG,"enable(): not allowed for non-active and non system user");
return false;
}
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
if (DBG) {
- Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
+ Slog.d(TAG,"enable(): mBluetooth =" + mBluetooth +
" mBinding = " + mBinding);
}
@@ -623,7 +621,7 @@
// waive WRITE_SECURE_SETTINGS permission check
sendEnableMsg(false);
}
- if (DBG) Log.d(TAG, "enable returning");
+ if (DBG) Slog.d(TAG, "enable returning");
return true;
}
@@ -633,12 +631,12 @@
if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
(!checkIfCallerIsForegroundUser())) {
- Log.w(TAG,"disable(): not allowed for non-active and non system user");
+ Slog.w(TAG,"disable(): not allowed for non-active and non system user");
return false;
}
if (DBG) {
- Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
+ Slog.d(TAG,"disable(): mBluetooth = " + mBluetooth +
" mBinding = " + mBinding);
}
@@ -657,7 +655,7 @@
public void unbindAndFinish() {
if (DBG) {
- Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
+ Slog.d(TAG,"unbindAndFinish(): " + mBluetooth +
" mBinding = " + mBinding);
}
@@ -669,10 +667,10 @@
try {
mBluetooth.unregisterCallback(mBluetoothCallback);
} catch (RemoteException re) {
- Log.e(TAG, "Unable to unregister BluetoothCallback",re);
+ Slog.e(TAG, "Unable to unregister BluetoothCallback",re);
}
- if (DBG) Log.d(TAG, "Sending unbind request.");
+ if (DBG) Slog.d(TAG, "Sending unbind request.");
mBluetoothBinder = null;
mBluetooth = null;
//Unbind
@@ -696,7 +694,7 @@
IBluetoothProfileServiceConnection proxy) {
if (!mEnable) {
if (DBG) {
- Log.d(TAG, "Trying to bind to profile: " + bluetoothProfile +
+ Slog.d(TAG, "Trying to bind to profile: " + bluetoothProfile +
", while Bluetooth was disabled");
}
return false;
@@ -705,7 +703,7 @@
ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
if (psc == null) {
if (DBG) {
- Log.d(TAG, "Creating new ProfileServiceConnections object for"
+ Slog.d(TAG, "Creating new ProfileServiceConnections object for"
+ " profile: " + bluetoothProfile);
}
@@ -746,7 +744,7 @@
try {
mContext.unbindService(psc);
} catch (IllegalArgumentException e) {
- Log.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
+ Slog.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
}
psc.removeAllProxies();
}
@@ -759,9 +757,9 @@
* PHASE_SYSTEM_SERVICES_READY.
*/
public void handleOnBootPhase() {
- if (DBG) Log.d(TAG, "Bluetooth boot completed");
+ if (DBG) Slog.d(TAG, "Bluetooth boot completed");
if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
- if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
+ if (DBG) Slog.d(TAG, "Auto-enabling Bluetooth.");
sendEnableMsg(mQuietEnableExternal);
}
}
@@ -770,8 +768,16 @@
* Called when switching to a different foreground user.
*/
public void handleOnSwitchUser(int userHandle) {
- if (DBG) Log.d(TAG, "Bluetooth user switched");
- mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED, userHandle, 0));
+ if (DBG) Slog.d(TAG, "User " + userHandle + " switched");
+ mHandler.obtainMessage(MESSAGE_USER_SWITCHED, userHandle, 0).sendToTarget();
+ }
+
+ /**
+ * Called when user is unlocked.
+ */
+ public void handleOnUnlockUser(int userHandle) {
+ if (DBG) Slog.d(TAG, "User " + userHandle + " unlocked");
+ mHandler.obtainMessage(MESSAGE_USER_UNLOCKED, userHandle, 0).sendToTarget();
}
/**
@@ -801,7 +807,7 @@
mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
return true;
}
- Log.w(TAG, "Unable to bind with intent: " + mIntent);
+ Slog.w(TAG, "Unable to bind with intent: " + mIntent);
return false;
}
@@ -811,7 +817,7 @@
try{
proxy.onServiceConnected(mClassName, mService);
} catch (RemoteException e) {
- Log.e(TAG, "Unable to connect to proxy", e);
+ Slog.e(TAG, "Unable to connect to proxy", e);
}
} else {
if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) {
@@ -828,11 +834,11 @@
try {
proxy.onServiceDisconnected(mClassName);
} catch (RemoteException e) {
- Log.e(TAG, "Unable to disconnect proxy", e);
+ Slog.e(TAG, "Unable to disconnect proxy", e);
}
}
} else {
- Log.w(TAG, "Trying to remove a null proxy");
+ Slog.w(TAG, "Trying to remove a null proxy");
}
}
@@ -850,11 +856,11 @@
try {
mService.linkToDeath(this, 0);
} catch (RemoteException e) {
- Log.e(TAG, "Unable to linkToDeath", e);
+ Slog.e(TAG, "Unable to linkToDeath", e);
}
if (mInvokingProxyCallbacks) {
- Log.e(TAG, "Proxy callbacks already in progress.");
+ Slog.e(TAG, "Proxy callbacks already in progress.");
return;
}
mInvokingProxyCallbacks = true;
@@ -865,7 +871,7 @@
try {
mProxies.getBroadcastItem(i).onServiceConnected(className, service);
} catch (RemoteException e) {
- Log.e(TAG, "Unable to connect to proxy", e);
+ Slog.e(TAG, "Unable to connect to proxy", e);
}
}
} finally {
@@ -882,7 +888,7 @@
mClassName = null;
if (mInvokingProxyCallbacks) {
- Log.e(TAG, "Proxy callbacks already in progress.");
+ Slog.e(TAG, "Proxy callbacks already in progress.");
return;
}
mInvokingProxyCallbacks = true;
@@ -893,7 +899,7 @@
try {
mProxies.getBroadcastItem(i).onServiceDisconnected(className);
} catch (RemoteException e) {
- Log.e(TAG, "Unable to disconnect from proxy", e);
+ Slog.e(TAG, "Unable to disconnect from proxy", e);
}
}
} finally {
@@ -905,7 +911,7 @@
@Override
public void binderDied() {
if (DBG) {
- Log.w(TAG, "Profile service for profile: " + mClassName
+ Slog.w(TAG, "Profile service for profile: " + mClassName
+ " died.");
}
onServiceDisconnected(mClassName);
@@ -919,12 +925,12 @@
private void sendBluetoothStateCallback(boolean isUp) {
try {
int n = mStateChangeCallbacks.beginBroadcast();
- if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
+ if (DBG) Slog.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
for (int i=0; i <n;i++) {
try {
mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
} catch (RemoteException e) {
- Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
+ Slog.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
}
}
} finally {
@@ -936,15 +942,15 @@
* Inform BluetoothAdapter instances that Adapter service is up
*/
private void sendBluetoothServiceUpCallback() {
- if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
+ if (DBG) Slog.d(TAG,"Calling onBluetoothServiceUp callbacks");
try {
int n = mCallbacks.beginBroadcast();
- Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
+ Slog.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
for (int i=0; i <n;i++) {
try {
mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
} catch (RemoteException e) {
- Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
+ Slog.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
}
}
} finally {
@@ -955,15 +961,15 @@
* Inform BluetoothAdapter instances that Adapter service is down
*/
private void sendBluetoothServiceDownCallback() {
- if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
+ if (DBG) Slog.d(TAG,"Calling onBluetoothServiceDown callbacks");
try {
int n = mCallbacks.beginBroadcast();
- Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
+ Slog.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
for (int i=0; i <n;i++) {
try {
mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
} catch (RemoteException e) {
- Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
+ Slog.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
}
}
} finally {
@@ -977,7 +983,7 @@
if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
(!checkIfCallerIsForegroundUser())) {
- Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
+ Slog.w(TAG,"getAddress(): not allowed for non-active and non system user");
return null;
}
@@ -991,7 +997,7 @@
try {
return mBluetooth.getAddress();
} catch (RemoteException e) {
- Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
+ Slog.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
}
}
}
@@ -1007,7 +1013,7 @@
if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
(!checkIfCallerIsForegroundUser())) {
- Log.w(TAG,"getName(): not allowed for non-active and non system user");
+ Slog.w(TAG,"getName(): not allowed for non-active and non system user");
return null;
}
@@ -1016,7 +1022,7 @@
try {
return mBluetooth.getName();
} catch (RemoteException e) {
- Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
+ Slog.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
}
}
}
@@ -1028,7 +1034,7 @@
private class BluetoothServiceConnection implements ServiceConnection {
public void onServiceConnected(ComponentName className, IBinder service) {
- if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
+ if (DBG) Slog.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
// TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
@@ -1037,7 +1043,7 @@
} else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
msg.arg1 = SERVICE_IBLUETOOTHGATT;
} else {
- Log.e(TAG, "Unknown service connected: " + className.getClassName());
+ Slog.e(TAG, "Unknown service connected: " + className.getClassName());
return;
}
msg.obj = service;
@@ -1046,7 +1052,7 @@
public void onServiceDisconnected(ComponentName className) {
// Called if we unexpected disconnected.
- if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
+ if (DBG) Slog.d(TAG, "BluetoothServiceConnection, disconnected: " +
className.getClassName());
Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
@@ -1054,7 +1060,7 @@
} else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
msg.arg1 = SERVICE_IBLUETOOTHGATT;
} else {
- Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
+ Slog.e(TAG, "Unknown service disconnected: " + className.getClassName());
return;
}
mHandler.sendMessage(msg);
@@ -1070,11 +1076,11 @@
@Override
public void handleMessage(Message msg) {
- if (DBG) Log.d (TAG, "Message: " + msg.what);
+ if (DBG) Slog.d (TAG, "Message: " + msg.what);
switch (msg.what) {
case MESSAGE_ENABLE:
if (DBG) {
- Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
+ Slog.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
}
mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mEnable = true;
@@ -1098,14 +1104,14 @@
{
IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
boolean added = mCallbacks.register(callback);
- Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
+ Slog.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
}
break;
case MESSAGE_UNREGISTER_ADAPTER:
{
IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
boolean removed = mCallbacks.unregister(callback);
- Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
+ Slog.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
break;
}
case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
@@ -1148,7 +1154,7 @@
}
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
{
- if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
+ if (DBG) Slog.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
IBinder service = (IBinder) msg.obj;
synchronized(mConnection) {
@@ -1169,17 +1175,17 @@
boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
- Log.e(TAG,"IBluetooth.configHciSnoopLog return false");
+ Slog.e(TAG,"IBluetooth.configHciSnoopLog return false");
}
} catch (RemoteException e) {
- Log.e(TAG,"Unable to call configHciSnoopLog", e);
+ Slog.e(TAG,"Unable to call configHciSnoopLog", e);
}
//Register callback object
try {
mBluetooth.registerCallback(mBluetoothCallback);
} catch (RemoteException re) {
- Log.e(TAG, "Unable to register BluetoothCallback",re);
+ Slog.e(TAG, "Unable to register BluetoothCallback",re);
}
//Inform BluetoothAdapter instances that service is up
sendBluetoothServiceUpCallback();
@@ -1188,17 +1194,17 @@
try {
if (mQuietEnable == false) {
if(!mBluetooth.enable()) {
- Log.e(TAG,"IBluetooth.enable() returned false");
+ Slog.e(TAG,"IBluetooth.enable() returned false");
}
}
else
{
if(!mBluetooth.enableNoAutoConnect()) {
- Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
+ Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
}
}
} catch (RemoteException e) {
- Log.e(TAG,"Unable to call enable()",e);
+ Slog.e(TAG,"Unable to call enable()",e);
}
}
@@ -1210,7 +1216,7 @@
break;
}
case MESSAGE_TIMEOUT_BIND: {
- Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
+ Slog.e(TAG, "MESSAGE_TIMEOUT_BIND");
synchronized(mConnection) {
mBinding = false;
}
@@ -1220,7 +1226,7 @@
{
int prevState = msg.arg1;
int newState = msg.arg2;
- if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
+ if (DBG) Slog.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
mState = newState;
bluetoothStateChangeHandler(prevState, newState);
// handle error state transition case from TURNING_ON to OFF
@@ -1239,7 +1245,7 @@
newState == BluetoothAdapter.STATE_BLE_ON) {
// bluetooth is working, reset the counter
if (mErrorRecoveryRetryCounter != 0) {
- Log.w(TAG, "bluetooth is recovered from error");
+ Slog.w(TAG, "bluetooth is recovered from error");
mErrorRecoveryRetryCounter = 0;
}
}
@@ -1247,7 +1253,7 @@
}
case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
{
- Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
+ Slog.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
synchronized(mConnection) {
if (msg.arg1 == SERVICE_IBLUETOOTH) {
// if service is unbinded already, do nothing and return
@@ -1257,7 +1263,7 @@
mBluetoothGatt = null;
break;
} else {
- Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
+ Slog.e(TAG, "Bad msg.arg1: " + msg.arg1);
break;
}
}
@@ -1292,7 +1298,7 @@
}
case MESSAGE_RESTART_BLUETOOTH_SERVICE:
{
- Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
+ Slog.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
+" Restart IBluetooth service");
/* Enable without persisting the setting as
it doesnt change when IBluetooth
@@ -1304,19 +1310,17 @@
case MESSAGE_TIMEOUT_UNBIND:
{
- Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
+ Slog.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
synchronized(mConnection) {
mUnbinding = false;
}
break;
}
- case MESSAGE_USER_SWITCHED:
- {
- if (DBG) {
- Log.d(TAG, "MESSAGE_USER_SWITCHED");
- }
+ case MESSAGE_USER_SWITCHED: {
+ if (DBG) Slog.d(TAG, "MESSAGE_USER_SWITCHED");
mHandler.removeMessages(MESSAGE_USER_SWITCHED);
+
/* disable and enable BT when detect a user switch */
if (mEnable && mBluetooth != null) {
synchronized (mConnection) {
@@ -1325,7 +1329,7 @@
try {
mBluetooth.unregisterCallback(mBluetoothCallback);
} catch (RemoteException re) {
- Log.e(TAG, "Unable to unregister",re);
+ Slog.e(TAG, "Unable to unregister",re);
}
}
}
@@ -1379,11 +1383,25 @@
// delay sending MESSAGE_USER_SWITCHED
mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
if (DBG) {
- Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
+ Slog.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
}
}
break;
}
+ case MESSAGE_USER_UNLOCKED: {
+ if (DBG) Slog.d(TAG, "MESSAGE_USER_UNLOCKED");
+ mHandler.removeMessages(MESSAGE_USER_SWITCHED);
+
+ synchronized (mConnection) {
+ if (mEnable && !mBinding && (mBluetooth == null)) {
+ // We should be connected, but we gave up for some
+ // reason; maybe the Bluetooth service wasn't encryption
+ // aware, so try binding again.
+ if (DBG) Slog.d(TAG, "Enabled but not bound; retrying after unlock");
+ handleEnable(mQuietEnable);
+ }
+ }
+ }
}
}
}
@@ -1408,16 +1426,16 @@
try {
if (!mQuietEnable) {
if(!mBluetooth.enable()) {
- Log.e(TAG,"IBluetooth.enable() returned false");
+ Slog.e(TAG,"IBluetooth.enable() returned false");
}
}
else {
if(!mBluetooth.enableNoAutoConnect()) {
- Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
+ Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
}
}
} catch (RemoteException e) {
- Log.e(TAG,"Unable to call enable()",e);
+ Slog.e(TAG,"Unable to call enable()",e);
}
}
}
@@ -1427,7 +1445,7 @@
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
- Log.e(TAG, "Fail to bind to: " + intent);
+ Slog.e(TAG, "Fail to bind to: " + intent);
return false;
}
return true;
@@ -1436,14 +1454,14 @@
private void handleDisable() {
synchronized(mConnection) {
if (mBluetooth != null) {
- if (DBG) Log.d(TAG,"Sending off request.");
+ if (DBG) Slog.d(TAG,"Sending off request.");
try {
if(!mBluetooth.disable()) {
- Log.e(TAG,"IBluetooth.disable() returned false");
+ Slog.e(TAG,"IBluetooth.disable() returned false");
}
} catch (RemoteException e) {
- Log.e(TAG,"Unable to call disable()",e);
+ Slog.e(TAG,"Unable to call disable()",e);
}
}
}
@@ -1466,7 +1484,7 @@
callingAppId == Process.NFC_UID ||
callingAppId == mSystemUiUid;
if (DBG) {
- Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
+ Slog.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
+ " callingUser=" + callingUser
+ " parentUser=" + parentUser
+ " foregroundUser=" + foregroundUser);
@@ -1478,7 +1496,7 @@
}
private void sendBleStateChanged(int prevState, int newState) {
- if (DBG) Log.d(TAG,"BLE State Change Intent: " + prevState + " -> " + newState);
+ if (DBG) Slog.d(TAG,"BLE State Change Intent: " + prevState + " -> " + newState);
// Send broadcast message to everyone else
Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
@@ -1498,9 +1516,9 @@
if (newState == BluetoothAdapter.STATE_OFF) {
// If Bluetooth is off, send service down event to proxy objects, and unbind
- if (DBG) Log.d(TAG, "Bluetooth is complete turn off");
+ if (DBG) Slog.d(TAG, "Bluetooth is complete turn off");
if (canUnbindBluetoothService()) {
- if (DBG) Log.d(TAG, "Good to unbind!");
+ if (DBG) Slog.d(TAG, "Good to unbind!");
sendBluetoothServiceDownCallback();
unbindAndFinish();
sendBleStateChanged(prevState, newState);
@@ -1510,12 +1528,12 @@
} else if (!intermediate_off) {
// connect to GattService
- if (DBG) Log.d(TAG, "Bluetooth is in LE only mode");
+ if (DBG) Slog.d(TAG, "Bluetooth is in LE only mode");
if (mBluetoothGatt != null) {
- if (DBG) Log.d(TAG, "Calling BluetoothGattServiceUp");
+ if (DBG) Slog.d(TAG, "Calling BluetoothGattServiceUp");
onBluetoothGattServiceUp();
} else {
- if (DBG) Log.d(TAG, "Binding Bluetooth GATT service");
+ if (DBG) Slog.d(TAG, "Binding Bluetooth GATT service");
if (mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_BLUETOOTH_LE)) {
Intent i = new Intent(IBluetoothGatt.class.getName());
@@ -1527,7 +1545,7 @@
isStandardBroadcast = false;
} else if (intermediate_off){
- if (DBG) Log.d(TAG, "Intermediate off, back to LE only mode");
+ if (DBG) Slog.d(TAG, "Intermediate off, back to LE only mode");
// For LE only mode, broadcast as is
sendBleStateChanged(prevState, newState);
sendBluetoothStateCallback(false); // BT is OFF for general users
@@ -1583,7 +1601,7 @@
if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
}
} catch (RemoteException e) {
- Log.e(TAG, "getState()", e);
+ Slog.e(TAG, "getState()", e);
break;
}
}
@@ -1594,7 +1612,7 @@
}
i++;
}
- Log.e(TAG,"waitForOnOff time out");
+ Slog.e(TAG,"waitForOnOff time out");
return false;
}
@@ -1619,21 +1637,21 @@
if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
} catch (RemoteException e) {
- Log.e(TAG, "getState()", e);
+ Slog.e(TAG, "getState()", e);
}
}
return false;
}
private void recoverBluetoothServiceFromError() {
- Log.e(TAG,"recoverBluetoothServiceFromError");
+ Slog.e(TAG,"recoverBluetoothServiceFromError");
synchronized (mConnection) {
if (mBluetooth != null) {
//Unregister callback object
try {
mBluetooth.unregisterCallback(mBluetoothCallback);
} catch (RemoteException re) {
- Log.e(TAG, "Unable to unregister",re);
+ Slog.e(TAG, "Unable to unregister",re);
}
}
}
diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java
index 019d03d..1bf4e3a 100644
--- a/services/core/java/com/android/server/BluetoothService.java
+++ b/services/core/java/com/android/server/BluetoothService.java
@@ -18,10 +18,8 @@
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
-import android.util.Log;
class BluetoothService extends SystemService {
- private static final String TAG = "BluetoothService";
private BluetoothManagerService mBluetoothManagerService;
public BluetoothService(Context context) {
@@ -36,17 +34,20 @@
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
- Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
- publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, mBluetoothManagerService);
+ publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE,
+ mBluetoothManagerService);
} else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
- Log.d(TAG, "onBootPhase: PHASE_ACTIVITY_MANAGER_READY");
mBluetoothManagerService.handleOnBootPhase();
}
}
@Override
public void onSwitchUser(int userHandle) {
- Log.d(TAG, "onSwitchUser: switching to user " + userHandle);
mBluetoothManagerService.handleOnSwitchUser(userHandle);
}
+
+ @Override
+ public void onUnlockUser(int userHandle) {
+ mBluetoothManagerService.handleOnUnlockUser(userHandle);
+ }
}
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..a93b4d8 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -39,6 +39,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.ActivityManagerNative;
import android.app.AlertDialog;
import android.app.AppGlobals;
@@ -47,7 +48,6 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.app.SynchronousUserSwitchObserver;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -465,7 +465,7 @@
super(handler);
}
- public void registerContentObserverLocked(int userId) {
+ public void registerContentObserverLocked(@UserIdInt int userId) {
if (mRegistered && mUserId == userId) {
return;
}
@@ -774,7 +774,16 @@
}
@Override
+ public void onSwitchUser(@UserIdInt int userHandle) {
+ // Called on the system server's main looper thread.
+ // TODO: Dispatch this to a worker thread as needed.
+ mService.onSwitchUser(userHandle);
+ }
+
+ @Override
public void onBootPhase(int phase) {
+ // Called on the system server's main looper thread.
+ // TODO: Dispatch this to a worker thread as needed.
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
StatusBarManagerService statusBarService = (StatusBarManagerService) ServiceManager
.getService(Context.STATUS_BAR_SERVICE);
@@ -783,12 +792,14 @@
}
@Override
- public void onUnlockUser(int userHandle) {
+ public void onUnlockUser(@UserIdInt int userHandle) {
+ // Called on the system server's main looper thread.
+ // TODO: Dispatch this to a worker thread as needed.
mService.onUnlockUser(userHandle);
}
}
- public void onUnlockUser(int userId) {
+ void onUnlockUser(@UserIdInt int userId) {
synchronized(mMethodMap) {
final int currentUserId = mSettings.getCurrentUserId();
if (DEBUG) {
@@ -804,6 +815,12 @@
}
}
+ void onSwitchUser(@UserIdInt int userId) {
+ synchronized (mMethodMap) {
+ switchUserLocked(userId);
+ }
+ }
+
public InputMethodManagerService(Context context) {
mIPackageManager = AppGlobals.getPackageManager();
mContext = context;
@@ -852,25 +869,6 @@
mNotificationShown = false;
int userId = 0;
try {
- ActivityManagerNative.getDefault().registerUserSwitchObserver(
- new SynchronousUserSwitchObserver() {
- @Override
- public void onUserSwitching(int newUserId)
- throws RemoteException {
- synchronized(mMethodMap) {
- switchUserLocked(newUserId);
- }
- }
-
- @Override
- public void onUserSwitchComplete(int newUserId) throws RemoteException {
- }
-
- @Override
- public void onForegroundProfileSwitch(int newProfileId) {
- // Ignore.
- }
- });
userId = ActivityManagerNative.getDefault().getCurrentUser().id;
} catch (RemoteException e) {
Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
@@ -1960,14 +1958,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/LockGuard.java b/services/core/java/com/android/server/LockGuard.java
new file mode 100644
index 0000000..3a381ae
--- /dev/null
+++ b/services/core/java/com/android/server/LockGuard.java
@@ -0,0 +1,149 @@
+/*
+ * 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;
+
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * LockGuard is a mechanism to help detect lock inversions inside the system
+ * server. It works by requiring each lock acquisition site to follow this
+ * pattern:
+ *
+ * <pre>
+ * synchronized (LockGuard.guard(lock)) {
+ * }
+ * </pre>
+ *
+ * <pre>
+ * $ find services/ -name "*.java" -exec sed -i -r \
+ * 's/synchronized.?\((.+?)\)/synchronized \(com.android.server.LockGuard.guard\(\1\)\)/' {} \;
+ * </pre>
+ *
+ * The {@link #guard(Object)} method internally verifies that all locking is
+ * done in a consistent order, and will log if any inversion is detected. For
+ * example, if the calling thread is trying to acquire the
+ * {@code ActivityManager} lock while holding the {@code PackageManager} lock,
+ * it will yell.
+ * <p>
+ * This class requires no prior knowledge of locks or their ordering; it derives
+ * all of this data at runtime. However, this means the overhead is
+ * <em>substantial</em> and it should not be enabled by default. For example,
+ * here are some benchmarked timings:
+ * <ul>
+ * <li>An unguarded synchronized block takes 40ns.
+ * <li>A guarded synchronized block takes 50ns when disabled.
+ * <li>A guarded synchronized block takes 460ns per lock checked when enabled.
+ * </ul>
+ */
+public class LockGuard {
+ private static final String TAG = "LockGuard";
+
+ private static ArrayMap<Object, LockInfo> sKnown = new ArrayMap<>(0, true);
+
+ private static class LockInfo {
+ /** Friendly label to describe this lock */
+ public String label;
+
+ /** Child locks that can be acquired while this lock is already held */
+ public ArraySet<Object> children = new ArraySet<>(0, true);
+ }
+
+ private static LockInfo findOrCreateLockInfo(Object lock) {
+ LockInfo info = sKnown.get(lock);
+ if (info == null) {
+ info = new LockInfo();
+ info.label = "0x" + Integer.toHexString(System.identityHashCode(lock)) + " ["
+ + new Throwable().getStackTrace()[2].toString() + "]";
+ sKnown.put(lock, info);
+ }
+ return info;
+ }
+
+ /**
+ * Check if the calling thread is holding any locks in an inverted order.
+ *
+ * @param lock The lock the calling thread is attempting to acquire.
+ */
+ public static Object guard(Object lock) {
+ // If we already hold this lock, ignore
+ if (lock == null || Thread.holdsLock(lock)) return lock;
+
+ // Check to see if we're already holding any child locks
+ boolean triggered = false;
+ final LockInfo info = findOrCreateLockInfo(lock);
+ for (int i = 0; i < info.children.size(); i++) {
+ final Object child = info.children.valueAt(i);
+ if (child == null) continue;
+
+ if (Thread.holdsLock(child)) {
+ Slog.w(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding "
+ + lockToString(child) + " while trying to acquire "
+ + lockToString(lock), new Throwable());
+ triggered = true;
+ }
+ }
+
+ if (!triggered) {
+ // If no trouble found above, record this lock as being a valid
+ // child of all locks currently being held
+ for (int i = 0; i < sKnown.size(); i++) {
+ final Object test = sKnown.keyAt(i);
+ if (test == null || test == lock) continue;
+
+ if (Thread.holdsLock(test)) {
+ sKnown.valueAt(i).children.add(lock);
+ }
+ }
+ }
+
+ return lock;
+ }
+
+ /**
+ * Report the given lock with a well-known label.
+ */
+ public static void installLock(Object lock, String label) {
+ final LockInfo info = findOrCreateLockInfo(lock);
+ info.label = label;
+ }
+
+ private static String lockToString(Object lock) {
+ final LockInfo info = sKnown.get(lock);
+ if (info != null) {
+ return info.label;
+ } else {
+ return "0x" + Integer.toHexString(System.identityHashCode(lock));
+ }
+ }
+
+ public static void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ for (int i = 0; i < sKnown.size(); i++) {
+ final Object lock = sKnown.keyAt(i);
+ final LockInfo info = sKnown.valueAt(i);
+ pw.println("Lock " + lockToString(lock) + ":");
+ for (int j = 0; j < info.children.size(); j++) {
+ pw.println(" Child " + lockToString(info.children.valueAt(j)));
+ }
+ pw.println();
+ }
+ }
+}
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/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index 3f0664d..b64c65d 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -23,8 +23,10 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
+import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
@@ -34,10 +36,14 @@
import android.provider.Settings;
import android.util.Log;
import android.util.NtpTrustedTime;
+import android.util.TimeUtils;
import android.util.TrustedTime;
import com.android.internal.telephony.TelephonyIntents;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* Monitors the network time and updates the system time if it is out of sync
* and there hasn't been any NITZ update from the carrier recently.
@@ -48,7 +54,7 @@
* available.
* </p>
*/
-public class NetworkTimeUpdateService {
+public class NetworkTimeUpdateService extends Binder {
private static final String TAG = "NetworkTimeUpdateService";
private static final boolean DBG = false;
@@ -59,6 +65,8 @@
private static final String ACTION_POLL =
"com.android.server.NetworkTimeUpdateService.action.POLL";
+
+ private static final int NETWORK_CHANGE_EVENT_DELAY_MS = 1000;
private static int POLL_REQUEST = 0;
private static final long NOT_SET = -1;
@@ -245,6 +253,7 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
+ if (DBG) Log.d(TAG, "Received " + action);
if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
mNitzTimeSetTime = SystemClock.elapsedRealtime();
} else if (TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE.equals(action)) {
@@ -260,8 +269,11 @@
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
+ if (DBG) Log.d(TAG, "Received CONNECTIVITY_ACTION ");
// Don't bother checking if we have connectivity, NtpTrustedTime does that for us.
- mHandler.obtainMessage(EVENT_NETWORK_CHANGED).sendToTarget();
+ Message message = mHandler.obtainMessage(EVENT_NETWORK_CHANGED);
+ // Send with a short delay to make sure the network is ready for use
+ mHandler.sendMessageDelayed(message, NETWORK_CHANGE_EVENT_DELAY_MS);
}
}
};
@@ -308,4 +320,28 @@
mHandler.obtainMessage(mMsg).sendToTarget();
}
}
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump NetworkTimeUpdateService from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " without permission "
+ + android.Manifest.permission.DUMP);
+ return;
+ }
+ pw.print("PollingIntervalMs: ");
+ TimeUtils.formatDuration(mPollingIntervalMs, pw);
+ pw.print("\nPollingIntervalShorterMs: ");
+ TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
+ pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
+ pw.print("TimeErrorThresholdMs: ");
+ TimeUtils.formatDuration(mTimeErrorThresholdMs, pw);
+ pw.println("\nTryAgainCounter: " + mTryAgainCounter);
+ pw.print("LastNtpFetchTime: ");
+ TimeUtils.formatDuration(mLastNtpFetchTime, pw);
+ pw.println();
+ }
}
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/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index c4b4cbe..3f453dc 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -27,9 +27,9 @@
import org.xmlpull.v1.XmlPullParserException;
+import android.annotation.UserIdInt;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
-import android.app.SynchronousUserSwitchObserver;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -76,16 +76,52 @@
private final Context mContext;
private boolean mSystemReady;
private final TextServicesMonitor mMonitor;
- private final HashMap<String, SpellCheckerInfo> mSpellCheckerMap =
- new HashMap<String, SpellCheckerInfo>();
- private final ArrayList<SpellCheckerInfo> mSpellCheckerList = new ArrayList<SpellCheckerInfo>();
- private final HashMap<String, SpellCheckerBindGroup> mSpellCheckerBindGroups =
- new HashMap<String, SpellCheckerBindGroup>();
+ private final HashMap<String, SpellCheckerInfo> mSpellCheckerMap = new HashMap<>();
+ private final ArrayList<SpellCheckerInfo> mSpellCheckerList = new ArrayList<>();
+ private final HashMap<String, SpellCheckerBindGroup> mSpellCheckerBindGroups = new HashMap<>();
private final TextServicesSettings mSettings;
- public void systemRunning() {
- if (!mSystemReady) {
- mSystemReady = true;
+ public static final class Lifecycle extends SystemService {
+ private TextServicesManagerService mService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ mService = new TextServicesManagerService(context);
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.TEXT_SERVICES_MANAGER_SERVICE, mService);
+ }
+
+ @Override
+ public void onSwitchUser(@UserIdInt int userHandle) {
+ // Called on the system server's main looper thread.
+ // TODO: Dispatch this to a worker thread as needed.
+ mService.onSwitchUser(userHandle);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ // Called on the system server's main looper thread.
+ // TODO: Dispatch this to a worker thread as needed.
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ mService.systemRunning();
+ }
+ }
+ }
+
+ void systemRunning() {
+ synchronized (mSpellCheckerMap) {
+ if (!mSystemReady) {
+ mSystemReady = true;
+ }
+ }
+ }
+
+ void onSwitchUser(@UserIdInt int userId) {
+ synchronized (mSpellCheckerMap) {
+ switchUserLocked(userId);
}
}
@@ -100,24 +136,6 @@
int userId = UserHandle.USER_SYSTEM;
try {
- ActivityManagerNative.getDefault().registerUserSwitchObserver(
- new SynchronousUserSwitchObserver() {
- @Override
- public void onUserSwitching(int newUserId) throws RemoteException {
- synchronized(mSpellCheckerMap) {
- switchUserLocked(newUserId);
- }
- }
-
- @Override
- public void onUserSwitchComplete(int newUserId) throws RemoteException {
- }
-
- @Override
- public void onForegroundProfileSwitch(int newProfileId) {
- // Ignore.
- }
- });
userId = ActivityManagerNative.getDefault().getCurrentUser().id;
} catch (RemoteException e) {
Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
@@ -130,7 +148,7 @@
switchUserLocked(userId);
}
- private void switchUserLocked(int userId) {
+ private void switchUserLocked(@UserIdInt int userId) {
mSettings.setCurrentUserId(userId);
updateCurrentProfileIds();
unbindServiceLocked();
@@ -615,8 +633,7 @@
Slog.d(TAG, "FinishSpellCheckerService");
}
synchronized(mSpellCheckerMap) {
- final ArrayList<SpellCheckerBindGroup> removeList =
- new ArrayList<SpellCheckerBindGroup>();
+ final ArrayList<SpellCheckerBindGroup> removeList = new ArrayList<>();
for (SpellCheckerBindGroup group : mSpellCheckerBindGroups.values()) {
if (group == null) continue;
// Use removeList to avoid modifying mSpellCheckerBindGroups in this loop.
@@ -811,7 +828,7 @@
private final String TAG = SpellCheckerBindGroup.class.getSimpleName();
private final InternalServiceConnection mInternalConnection;
private final CopyOnWriteArrayList<InternalDeathRecipient> mListeners =
- new CopyOnWriteArrayList<InternalDeathRecipient>();
+ new CopyOnWriteArrayList<>();
public boolean mBound;
public ISpellCheckerService mSpellChecker;
public boolean mConnected;
@@ -885,8 +902,7 @@
}
synchronized(mSpellCheckerMap) {
final int size = mListeners.size();
- final ArrayList<InternalDeathRecipient> removeList =
- new ArrayList<InternalDeathRecipient>();
+ final ArrayList<InternalDeathRecipient> removeList = new ArrayList<>();
for (int i = 0; i < size; ++i) {
final InternalDeathRecipient tempRecipient = mListeners.get(i);
if(tempRecipient.hasSpellCheckerListener(listener)) {
@@ -1015,17 +1031,18 @@
private static class TextServicesSettings {
private final ContentResolver mResolver;
+ @UserIdInt
private int mCurrentUserId;
@GuardedBy("mLock")
private int[] mCurrentProfileIds = new int[0];
private Object mLock = new Object();
- public TextServicesSettings(ContentResolver resolver, int userId) {
+ public TextServicesSettings(ContentResolver resolver, @UserIdInt int userId) {
mResolver = resolver;
mCurrentUserId = userId;
}
- public void setCurrentUserId(int userId) {
+ public void setCurrentUserId(@UserIdInt int userId) {
if (DBG) {
Slog.d(TAG, "--- Swtich the current user from " + mCurrentUserId + " to "
+ userId + ", new ime = " + getSelectedSpellChecker());
@@ -1034,13 +1051,37 @@
mCurrentUserId = userId;
}
+ private void putString(final String key, final String str) {
+ Settings.Secure.putStringForUser(mResolver, key, str, mCurrentUserId);
+ }
+
+ private String getString(final String key) {
+ return Settings.Secure.getStringForUser(mResolver, key, mCurrentUserId);
+ }
+
+ private void putInt(final String key, final int value) {
+ Settings.Secure.putIntForUser(mResolver, key, value, mCurrentUserId);
+ }
+
+ private int getInt(final String key, final int defaultValue) {
+ return Settings.Secure.getIntForUser(mResolver, key, defaultValue, mCurrentUserId);
+ }
+
+ private void putBoolean(final String key, final boolean value) {
+ putInt(key, value ? 1 : 0);
+ }
+
+ private boolean getBoolean(final String key, final boolean defaultValue) {
+ return getInt(key, defaultValue ? 1 : 0) == 1;
+ }
+
public void setCurrentProfileIds(int[] currentProfileIds) {
synchronized (mLock) {
mCurrentProfileIds = currentProfileIds;
}
}
- public boolean isCurrentProfile(int userId) {
+ public boolean isCurrentProfile(@UserIdInt int userId) {
synchronized (mLock) {
if (userId == mCurrentUserId) return true;
for (int i = 0; i < mCurrentProfileIds.length; i++) {
@@ -1050,39 +1091,33 @@
}
}
+ @UserIdInt
public int getCurrentUserId() {
return mCurrentUserId;
}
public void putSelectedSpellChecker(String sciId) {
- Settings.Secure.putStringForUser(mResolver,
- Settings.Secure.SELECTED_SPELL_CHECKER, sciId, mCurrentUserId);
+ putString(Settings.Secure.SELECTED_SPELL_CHECKER, sciId);
}
public void putSelectedSpellCheckerSubtype(int hashCode) {
- Settings.Secure.putStringForUser(mResolver,
- Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, String.valueOf(hashCode),
- mCurrentUserId);
+ putString(Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, String.valueOf(hashCode));
}
public void setSpellCheckerEnabled(boolean enabled) {
- Settings.Secure.putIntForUser(mResolver,
- Settings.Secure.SPELL_CHECKER_ENABLED, enabled ? 1 : 0, mCurrentUserId);
+ putBoolean(Settings.Secure.SPELL_CHECKER_ENABLED, enabled);
}
public String getSelectedSpellChecker() {
- return Settings.Secure.getStringForUser(mResolver,
- Settings.Secure.SELECTED_SPELL_CHECKER, mCurrentUserId);
+ return getString(Settings.Secure.SELECTED_SPELL_CHECKER);
}
public String getSelectedSpellCheckerSubtype() {
- return Settings.Secure.getStringForUser(mResolver,
- Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, mCurrentUserId);
+ return getString(Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE);
}
public boolean isSpellCheckerEnabled() {
- return Settings.Secure.getIntForUser(mResolver,
- Settings.Secure.SPELL_CHECKER_ENABLED, 1, mCurrentUserId) == 1;
+ return getBoolean(Settings.Secure.SPELL_CHECKER_ENABLED, true);
}
}
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 c81ee2c..0317641 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -45,6 +45,7 @@
import com.android.server.DeviceIdleController;
import com.android.server.IntentResolver;
import com.android.server.LocalServices;
+import com.android.server.LockGuard;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
@@ -100,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;
@@ -283,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;
@@ -1293,6 +1297,7 @@
boolean mAlwaysFinishActivities = false;
boolean mLenientBackgroundCheck = false;
boolean mForceResizableActivities;
+ boolean mSupportsMultiWindow;
boolean mSupportsFreeformWindowManagement;
boolean mSupportsPictureInPicture;
Rect mDefaultPinnedStackBounds;
@@ -1895,6 +1900,9 @@
final int userId = msg.arg1;
mSystemServiceManager.unlockUser(userId);
mRecentTasks.loadUserRecentsLocked(userId);
+ if (userId == UserHandle.USER_SYSTEM) {
+ startPersistentApps(PackageManager.MATCH_ENCRYPTION_UNAWARE);
+ }
installEncryptionUnawareProviders(userId);
break;
}
@@ -2148,15 +2156,20 @@
} break;
case VR_MODE_CHANGE_MSG: {
VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
- final boolean vrMode = msg.arg1 != 0;
- vrService.setVrMode(vrMode);
-
- if (mInVrMode != vrMode) {
- synchronized (ActivityManagerService.this) {
+ final ActivityRecord r = (ActivityRecord) msg.obj;
+ boolean vrMode;
+ ComponentName requestedPackage;
+ int userId;
+ synchronized (ActivityManagerService.this) {
+ vrMode = r.requestedVrComponent != null;
+ requestedPackage = r.requestedVrComponent;
+ userId = r.userId;
+ if (mInVrMode != vrMode) {
mInVrMode = vrMode;
mShowDialogs = shouldShowDialogs(mConfiguration, mInVrMode);
}
}
+ vrService.setVrMode(vrMode, requestedPackage, userId);
} break;
}
}
@@ -2929,7 +2942,7 @@
final void applyUpdateVrModeLocked(ActivityRecord r) {
mHandler.sendMessage(
- mHandler.obtainMessage(VR_MODE_CHANGE_MSG, (r.isVrActivity) ? 1 : 0, 0));
+ mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r));
}
final void showAskCompatModeDialogLocked(ActivityRecord r) {
@@ -4368,7 +4381,7 @@
AppGlobals.getPackageManager().queryIntentActivities(
intent, r.resolvedType,
PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS,
- UserHandle.getCallingUserId());
+ UserHandle.getCallingUserId()).getList();
// Look for the original activity in the list...
final int N = resolves != null ? resolves.size() : 0;
@@ -5086,8 +5099,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) {
@@ -5100,7 +5118,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");
}
}
}
@@ -5127,13 +5149,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);
}
}
}
@@ -5239,9 +5268,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,
@@ -5355,17 +5388,6 @@
@Override
public void killAllBackgroundProcesses() {
- killAllBackgroundProcesses(-1);
- }
-
- /**
- * Kills all background processes with targetSdkVersion below the specified
- * target SDK version.
- *
- * @param targetSdkVersion the target SDK version below which to kill
- * processes, or {@code -1} to kill all processes
- */
- private void killAllBackgroundProcesses(int targetSdkVersion) {
if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
!= PackageManager.PERMISSION_GRANTED) {
final String msg = "Permission Denial: killAllBackgroundProcesses() from pid="
@@ -5389,10 +5411,6 @@
// We don't kill persistent processes.
continue;
}
- if (targetSdkVersion > 0
- && app.info.targetSdkVersion >= targetSdkVersion) {
- continue;
- }
if (app.removed) {
procs.add(app);
} else if (app.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
@@ -5417,6 +5435,55 @@
}
}
+ /**
+ * Kills all background processes, except those matching any of the
+ * specified properties.
+ *
+ * @param minTargetSdk the target SDK version at or above which to preserve
+ * processes, or {@code -1} to ignore the target SDK
+ * @param maxProcState the process state at or below which to preserve
+ * processes, or {@code -1} to ignore the process state
+ */
+ private void killAllBackgroundProcessesExcept(int minTargetSdk, int maxProcState) {
+ if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
+ != PackageManager.PERMISSION_GRANTED) {
+ final String msg = "Permission Denial: killAllBackgroundProcessesExcept() from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final ArrayList<ProcessRecord> procs = new ArrayList<>();
+ final int NP = mProcessNames.getMap().size();
+ for (int ip = 0; ip < NP; ip++) {
+ final SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
+ final int NA = apps.size();
+ for (int ia = 0; ia < NA; ia++) {
+ final ProcessRecord app = apps.valueAt(ia);
+ if (app.removed) {
+ procs.add(app);
+ } else if ((minTargetSdk < 0 || app.info.targetSdkVersion < minTargetSdk)
+ && (maxProcState < 0 || app.setProcState > maxProcState)) {
+ app.removed = true;
+ procs.add(app);
+ }
+ }
+ }
+
+ final int N = procs.size();
+ for (int i = 0; i < N; i++) {
+ removeProcessLocked(procs.get(i), false, true, "kill all background except");
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
@Override
public void forceStopPackage(final String packageName, int userId) {
if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
@@ -6173,7 +6240,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;
@@ -6231,9 +6298,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
@@ -9164,7 +9232,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 {
@@ -9489,7 +9557,7 @@
* docked stack. Pass {@code null} to use default bounds.
*/
@Override
- public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
+ public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
Rect initialBounds) {
enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToDockedStack()");
synchronized (this) {
@@ -9498,7 +9566,8 @@
if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToDockedStack: moving task=" + taskId
+ " to createMode=" + createMode + " toTop=" + toTop);
mWindowManager.setDockedStackCreateState(createMode, initialBounds);
- mStackSupervisor.moveTaskToStackLocked(taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS,
+ return mStackSupervisor.moveTaskToStackLocked(
+ taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS,
"moveTaskToDockedStack", animate);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -9577,6 +9646,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) {
@@ -9830,11 +9913,11 @@
private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
List<ProviderInfo> providers = null;
try {
- ParceledListSlice<ProviderInfo> slice = AppGlobals.getPackageManager()
+ providers = AppGlobals.getPackageManager()
.queryContentProviders(app.processName, app.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
- | MATCH_DEBUG_TRIAGED_MISSING);
- providers = slice != null ? slice.getList() : null;
+ | MATCH_DEBUG_TRIAGED_MISSING)
+ .getList();
} catch (RemoteException ex) {
}
if (DEBUG_MU) Slog.v(TAG_MU,
@@ -10424,7 +10507,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) {
@@ -10744,12 +10827,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() {
@@ -10778,6 +10862,23 @@
//mUsageStatsService.monitorPackages();
}
+ private void startPersistentApps(int matchFlags) {
+ if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;
+
+ synchronized (this) {
+ try {
+ final List<ApplicationInfo> apps = AppGlobals.getPackageManager()
+ .getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
+ for (ApplicationInfo app : apps) {
+ if (!"android".equals(app.packageName)) {
+ addAppLocked(app, false, null /* ABI override */);
+ }
+ }
+ } catch (RemoteException ex) {
+ }
+ }
+ }
+
/**
* When a user is unlocked, we need to install encryption-unaware providers
* belonging to any running apps.
@@ -10794,8 +10895,7 @@
// We're only interested in providers that are encryption unaware, and
// we don't care about uninstalled apps, since there's no way they're
// running at this point.
- final int matchFlags = GET_PROVIDERS | MATCH_ENCRYPTION_UNAWARE
- | MATCH_DEBUG_TRIAGED_MISSING;
+ final int matchFlags = GET_PROVIDERS | MATCH_ENCRYPTION_UNAWARE;
synchronized (this) {
final int NP = mProcessNames.getMap().size();
@@ -11935,25 +12035,51 @@
}
@Override
- public void setVrMode(IBinder token, boolean enabled) {
+ public int setVrMode(IBinder token, boolean enabled, ComponentName packageName) {
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
throw new UnsupportedOperationException("VR mode not supported on this device!");
}
+ final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
+
+ ActivityRecord r;
+ synchronized (this) {
+ r = ActivityRecord.isInStackLocked(token);
+ }
+
+ if (r == null) {
+ throw new IllegalArgumentException();
+ }
+
+ int err;
+ if ((err = vrService.hasVrPackage(packageName, r.userId)) !=
+ VrManagerInternal.NO_ERROR) {
+ return err;
+ }
+
synchronized(this) {
- final ActivityRecord r = ActivityRecord.isInStackLocked(token);
- if (r == null) {
- throw new IllegalArgumentException();
- }
- r.isVrActivity = enabled;
+ r.requestedVrComponent = (enabled) ? packageName : null;
// Update associated state if this activity is currently focused
if (r == mFocusedActivity) {
applyUpdateVrModeLocked(r);
}
+ return 0;
}
}
+ @Override
+ public boolean isVrModePackageEnabled(ComponentName packageName) {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
+ throw new UnsupportedOperationException("VR mode not supported on this device!");
+ }
+
+ final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
+
+ return vrService.hasVrPackage(packageName, UserHandle.getCallingUserId()) ==
+ VrManagerInternal.NO_ERROR;
+ }
+
public boolean isTopActivityImmersive() {
enforceNotIsolatedCaller("startActivity");
synchronized (this) {
@@ -12316,6 +12442,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 =
@@ -12342,8 +12469,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);
@@ -12511,7 +12645,7 @@
List<ResolveInfo> ris = null;
try {
ris = AppGlobals.getPackageManager().queryIntentReceivers(
- intent, null, MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
+ intent, null, MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM).getList();
} catch (RemoteException e) {
}
if (ris == null) {
@@ -12681,26 +12815,9 @@
mSystemServiceManager.startUser(currentUserId);
synchronized (this) {
- if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
- try {
- List apps = AppGlobals.getPackageManager().
- getPersistentApplications(STOCK_PM_FLAGS);
- if (apps != null) {
- int N = apps.size();
- int i;
- for (i=0; i<N; i++) {
- ApplicationInfo info
- = (ApplicationInfo)apps.get(i);
- if (info != null &&
- !info.packageName.equals("android")) {
- addAppLocked(info, false, null /* ABI override */);
- }
- }
- }
- } catch (RemoteException ex) {
- // pm is in same process, this will never happen.
- }
- }
+ // Only start up encryption-aware persistent apps; once user is
+ // unlocked we'll come back around and start unaware apps
+ startPersistentApps(PackageManager.MATCH_ENCRYPTION_AWARE);
// Start up initial activity.
mBooting = true;
@@ -13585,6 +13702,8 @@
synchronized (this) {
mServices.dumpServicesLocked(fd, pw, args, opti, true, dumpClient, dumpPackage);
}
+ } else if ("locks".equals(cmd)) {
+ LockGuard.dump(fd, pw, args);
} else {
// Dumping a single activity?
if (!dumpActivity(fd, pw, cmd, args, opti, dumpAll)) {
@@ -14731,13 +14850,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:
@@ -16875,7 +16994,7 @@
continue;
}
List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
- .queryIntentReceivers(intent, resolvedType, pmFlags, user);
+ .queryIntentReceivers(intent, resolvedType, pmFlags, user).getList();
if (user != UserHandle.USER_SYSTEM && newReceivers != null) {
// If this is not the system user, we need to check for
// any receivers that should be filtered out.
@@ -17145,10 +17264,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)),
@@ -17156,7 +17276,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(
@@ -17191,7 +17314,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;
@@ -17209,6 +17348,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
@@ -18050,7 +18190,8 @@
final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
if (isDensityChange) {
- killAllBackgroundProcesses(Build.VERSION_CODES.N);
+ killAllBackgroundProcessesExcept(Build.VERSION_CODES.N,
+ ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
}
for (int i=mLruProcesses.size()-1; i>=0; i--) {
@@ -18271,7 +18412,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);
}
@@ -18291,7 +18432,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
@@ -18328,14 +18469,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) {
@@ -18345,7 +18486,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) {
@@ -18353,13 +18494,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;
@@ -18388,7 +18529,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;
@@ -18407,7 +18548,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;
@@ -18451,7 +18592,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;
@@ -18459,7 +18600,7 @@
app.cached = false;
app.adjType = "force-fg";
app.adjSource = app.forcingToForeground;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
}
@@ -18467,7 +18608,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";
}
@@ -18481,7 +18622,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";
}
@@ -18496,7 +18637,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";
}
@@ -18536,7 +18677,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);
@@ -18574,13 +18715,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
@@ -18672,7 +18813,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) {
@@ -18742,9 +18883,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;
@@ -18762,13 +18903,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);
@@ -18826,7 +18967,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
@@ -18835,7 +18976,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;
@@ -18849,7 +18990,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";
}
@@ -18928,7 +19069,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;
}
}
@@ -19344,17 +19485,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);
@@ -19365,7 +19518,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/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 0e6dd28..43e1bdf 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -61,7 +61,7 @@
mLastLogTimeSecs = now;
ActivityStack stack = mSupervisor.getStack(DOCKED_STACK_ID);
- if (stack != null && stack.getStackVisibilityLocked() != STACK_INVISIBLE) {
+ if (stack != null && stack.getStackVisibilityLocked(null) != STACK_INVISIBLE) {
mWindowState = WINDOW_STATE_SIDE_BY_SIDE;
return;
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index d5e40cf..2ea5d15 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;
@@ -122,7 +123,7 @@
final boolean stateNotNeeded; // As per ActivityInfo.flags
boolean fullscreen; // covers the full screen?
final boolean noDisplay; // activity is not displayed?
- final boolean componentSpecified; // did caller specifiy an explicit component?
+ final boolean componentSpecified; // did caller specify an explicit component?
final boolean rootVoiceInteraction; // was this the root activity of a voice interaction?
static final int APPLICATION_ACTIVITY_TYPE = 0;
@@ -189,7 +190,7 @@
boolean forceNewConfig; // force re-create with new config next time
int launchCount; // count of launches since last state
long lastLaunchTime; // time of last launch of this activity
- boolean isVrActivity; // is the activity running in VR mode?
+ ComponentName requestedVrComponent; // the requested component for handling VR mode.
ArrayList<ActivityContainer> mChildContainers = new ArrayList<>();
String stringName; // for caching of toString().
@@ -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);
@@ -349,7 +354,11 @@
pw.print(" forceNewConfig="); pw.println(forceNewConfig);
pw.print(prefix); pw.print("mActivityType=");
pw.println(activityTypeToString(mActivityType));
- pw.print(prefix); pw.print("vrMode="); pw.println(isVrActivity);
+ if (requestedVrComponent != null) {
+ pw.print(prefix);
+ pw.print("requestedVrComponent=");
+ pw.println(requestedVrComponent);
+ }
if (displayStartTime != 0 || startTime != 0) {
pw.print(prefix); pw.print("displayStartTime=");
if (displayStartTime == 0) pw.print("0");
@@ -713,7 +722,6 @@
}
immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0;
- isVrActivity = (aInfo.flags & ActivityInfo.FLAG_ENABLE_VR_MODE) != 0;
} else {
realActivity = null;
taskAffinity = null;
@@ -725,7 +733,6 @@
noDisplay = false;
mActivityType = APPLICATION_ACTIVITY_TYPE;
immersive = false;
- isVrActivity = false;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 769bee4..e50722a 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -65,6 +65,7 @@
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Uri;
@@ -184,7 +185,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 +840,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 +1114,7 @@
r.stopped = true;
r.state = ActivityState.STOPPED;
- mWindowManager.notifyAppStopped(r.appToken);
+ mWindowManager.notifyAppStopped(r.appToken, true);
if (getVisibleBehindActivity() == r) {
mStackSupervisor.requestVisibleBehindLocked(r, false);
@@ -1354,7 +1367,7 @@
for (int i = stacks.size() - 1; i >= 0; --i) {
ActivityStack stack = stacks.get(i);
if (stack != this && stack.isFocusable()
- && stack.getStackVisibilityLocked() != STACK_INVISIBLE) {
+ && stack.getStackVisibilityLocked(null) != STACK_INVISIBLE) {
return stack;
}
}
@@ -1373,21 +1386,26 @@
return false;
}
- private boolean hasTranslucentActivity(ActivityStack stack) {
- final ArrayList<TaskRecord> tasks = stack.getAllTasks();
- for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = tasks.get(taskNdx);
+ /**
+ * Returns true if the stack is translucent and can have other contents visible behind it if
+ * needed. A stack is considered translucent if it don't contain a visible or
+ * starting (about to be visible) activity that is fullscreen (opaque).
+ * @param starting The currently starting activity or null if there is none.
+ */
+ private boolean isStackTranslucent(ActivityRecord starting) {
+ for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+ final TaskRecord task = mTaskHistory.get(taskNdx);
final ArrayList<ActivityRecord> activities = task.mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
// Conditions for an activity to obscure the stack we're
// examining:
- // 1. Not Finishing AND Visible AND:
+ // 1. Not Finishing AND (Visible or the Starting activity) AND:
// 2. Either:
// - Full Screen Activity OR
// - On top of Home and our stack is NOT home
- if (!r.finishing && r.visible && (r.fullscreen ||
+ if (!r.finishing && (r.visible || r == starting) && (r.fullscreen ||
(!isHomeStack() && r.frontOfTask && task.isOverHomeStack()))) {
return false;
}
@@ -1399,8 +1417,9 @@
/**
* Returns stack's visibility: {@link #STACK_INVISIBLE}, {@link #STACK_VISIBLE} or
* {@link #STACK_VISIBLE_ACTIVITY_BEHIND}.
+ * @param starting The currently starting activity or null if there is none.
*/
- int getStackVisibilityLocked() {
+ int getStackVisibilityLocked(ActivityRecord starting) {
if (!isAttached()) {
return STACK_INVISIBLE;
}
@@ -1456,7 +1475,7 @@
}
if (focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID
- && hasTranslucentActivity(focusedStack)) {
+ && focusedStack.isStackTranslucent(starting)) {
// Stacks behind the fullscreen stack with a translucent activity are always
// visible so they can act as a backdrop to the translucent activity.
// For example, dialog activities
@@ -1491,7 +1510,7 @@
return STACK_INVISIBLE;
}
- if (!hasTranslucentActivity(stack)) {
+ if (!stack.isStackTranslucent(starting)) {
return STACK_INVISIBLE;
}
}
@@ -1529,7 +1548,7 @@
// If the top activity is not fullscreen, then we need to
// make sure any activities under it are now visible.
boolean aboveTop = top != null;
- final int stackVisibility = getStackVisibilityLocked();
+ final int stackVisibility = getStackVisibilityLocked(starting);
final boolean stackInvisible = stackVisibility != STACK_VISIBLE;
final boolean stackVisibleBehind = stackVisibility == STACK_VISIBLE_ACTIVITY_BEHIND;
boolean behindFullscreenActivity = stackInvisible;
@@ -2233,6 +2252,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);
@@ -3788,7 +3811,8 @@
void releaseBackgroundResources(ActivityRecord r) {
if (hasVisibleBehindActivity() &&
!mHandler.hasMessages(RELEASE_BACKGROUND_RESOURCES_TIMEOUT_MSG)) {
- if (r == topRunningActivityLocked() && getStackVisibilityLocked() == STACK_VISIBLE) {
+ if (r == topRunningActivityLocked()
+ && getStackVisibilityLocked(null) == STACK_VISIBLE) {
// Don't release the top activity if it has requested to run behind the next
// activity and the stack is currently visible.
return;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c7fc5e2..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
@@ -2213,18 +2245,18 @@
return stack;
}
- void moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,
+ boolean moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,
String reason, boolean animate) {
final TaskRecord task = anyTaskForIdLocked(taskId);
if (task == null) {
Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId);
- return;
+ return false;
}
if (task.stack != null && task.stack.mStackId == stackId) {
// You are already in the right stack silly...
Slog.i(TAG, "moveTaskToStack: taskId=" + taskId + " already in stackId=" + stackId);
- return;
+ return true;
}
if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) {
@@ -2293,6 +2325,8 @@
resumeFocusedStackTopActivityLocked();
showNonResizeableDockToastIfNeeded(task, preferredLaunchStackId, stackId);
+
+ return (preferredLaunchStackId == stackId);
}
boolean moveTopStackActivityToPinnedStackLocked(int stackId, Rect bounds) {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index bcdc800..83ad2a7 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1757,7 +1757,7 @@
// and if yes, we will launch into that stack. If not, we just put the new
// activity into parent's stack, because we can't find a better place.
final ActivityStack stack = mSupervisor.getStack(DOCKED_STACK_ID);
- if (stack != null && stack.getStackVisibilityLocked() == STACK_INVISIBLE) {
+ if (stack != null && stack.getStackVisibilityLocked(r) == STACK_INVISIBLE) {
// There is a docked stack, but it isn't visible, so we can't launch into that.
return null;
} else {
@@ -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/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
index 86cdbcc..ddfab4d 100644
--- a/services/core/java/com/android/server/am/AppErrorDialog.java
+++ b/services/core/java/com/android/server/am/AppErrorDialog.java
@@ -25,6 +25,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.text.BidiFormatter;
import android.util.Slog;
import android.view.LayoutInflater;
import android.view.View;
@@ -68,18 +69,21 @@
mProc = data.proc;
mResult = data.result;
mRepeating = data.repeating;
+ BidiFormatter bidi = BidiFormatter.getInstance();
+
if ((mProc.pkgList.size() == 1) &&
(mName = context.getPackageManager().getApplicationLabel(mProc.info)) != null) {
setTitle(res.getString(
mRepeating ? com.android.internal.R.string.aerr_application_repeated
: com.android.internal.R.string.aerr_application,
- mName.toString(), mProc.info.processName));
+ bidi.unicodeWrap(mName.toString()),
+ bidi.unicodeWrap(mProc.info.processName)));
} else {
mName = mProc.processName;
setTitle(res.getString(
mRepeating ? com.android.internal.R.string.aerr_process_repeated
: com.android.internal.R.string.aerr_process,
- mName.toString()));
+ bidi.unicodeWrap(mName.toString())));
}
setCancelable(false);
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/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index 6d1d9f3..c6befd7 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -27,6 +27,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.text.BidiFormatter;
import android.util.Slog;
import android.view.LayoutInflater;
import android.view.View;
@@ -84,9 +85,11 @@
}
}
+ BidiFormatter bidi = BidiFormatter.getInstance();
+
setTitle(name2 != null
- ? res.getString(resid, name1.toString(), name2.toString())
- : res.getString(resid, name1.toString()));
+ ? res.getString(resid, bidi.unicodeWrap(name1.toString()), bidi.unicodeWrap(name2.toString()))
+ : res.getString(resid, bidi.unicodeWrap(name1.toString())));
if (aboveSystem) {
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
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..d919737 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -58,7 +58,7 @@
import android.media.AudioManager;
import android.media.AudioManagerInternal;
import android.media.AudioPort;
-import android.media.AudioRecordConfiguration;
+import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioRoutesObserver;
@@ -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;
}
}
}
@@ -6253,8 +6287,8 @@
mRecordMonitor.unregisterRecordingCallback(rcdb);
}
- public AudioRecordConfiguration[] getActiveRecordConfigurations() {
- return mRecordMonitor.getActiveRecordConfigurations();
+ public AudioRecordingConfiguration[] getActiveRecordingConfigurations() {
+ return mRecordMonitor.getActiveRecordingConfigurations();
}
//======================
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
index 7e76ac4..7a085e1 100644
--- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -18,7 +18,7 @@
import android.media.AudioFormat;
import android.media.AudioManager;
-import android.media.AudioRecordConfiguration;
+import android.media.AudioRecordingConfiguration;
import android.media.AudioSystem;
import android.media.IRecordingConfigDispatcher;
import android.media.MediaRecorder;
@@ -39,8 +39,8 @@
private ArrayList<RecMonitorClient> mClients = new ArrayList<RecMonitorClient>();
- private HashMap<Integer, AudioRecordConfiguration> mRecordConfigs =
- new HashMap<Integer, AudioRecordConfiguration>();
+ private HashMap<Integer, AudioRecordingConfiguration> mRecordConfigs =
+ new HashMap<Integer, AudioRecordingConfiguration>();
RecordingActivityMonitor() {
RecMonitorClient.sMonitor = this;
@@ -54,12 +54,15 @@
if (MediaRecorder.isSystemOnlyAudioSource(source)) {
return;
}
- if (updateSnapshot(event, session, source, recordingInfo)) {
- final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
+ final AudioRecordingConfiguration[] 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);
}
@@ -101,9 +104,9 @@
}
}
- AudioRecordConfiguration[] getActiveRecordConfigurations() {
+ AudioRecordingConfiguration[] getActiveRecordingConfigurations() {
synchronized(mRecordConfigs) {
- return mRecordConfigs.values().toArray(new AudioRecordConfiguration[0]);
+ return mRecordConfigs.values().toArray(new AudioRecordingConfiguration[0]);
}
}
@@ -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 AudioRecordingConfiguration[] updateSnapshot(int event, int session, int source,
+ int[] recordingInfo) {
+ final boolean configChanged;
+ final AudioRecordingConfiguration[] 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])
@@ -139,29 +147,36 @@
final int patchHandle = recordingInfo[6];
final Integer sessionKey = new Integer(session);
if (mRecordConfigs.containsKey(sessionKey)) {
- final AudioRecordConfiguration updatedConfig =
- new AudioRecordConfiguration(session, source,
+ final AudioRecordingConfiguration updatedConfig =
+ new AudioRecordingConfiguration(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,
+ new AudioRecordingConfiguration(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 AudioRecordingConfiguration[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 4504bdb..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;
@@ -566,7 +566,7 @@
@Override
public void enter() {
final String cmdName = ACTION_LINGER_EXPIRED + "." + mNetworkAgentInfo.network.netId;
- mWakeupMessage = new WakeupMessage(mContext, getHandler(), cmdName, CMD_LINGER_EXPIRED);
+ mWakeupMessage = makeWakeupMessage(mContext, getHandler(), cmdName, CMD_LINGER_EXPIRED);
long wakeupTime = SystemClock.elapsedRealtime() + mLingerDelayMs;
mWakeupMessage.schedule(wakeupTime);
}
@@ -823,4 +823,9 @@
}
DEFAULT_LINGER_DELAY_MS = time_ms;
}
+
+ @VisibleForTesting
+ protected WakeupMessage makeWakeupMessage(Context c, Handler h, String s, int i) {
+ return new WakeupMessage(c, h, s, i);
+ }
}
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/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 0d6e3e5..17313b6 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -301,7 +302,9 @@
* */
public void registerGuestService(ManagedServiceInfo guest) {
checkNotNull(guest.service);
- checkType(guest.service);
+ if (!checkType(guest.service)) {
+ throw new IllegalArgumentException();
+ }
if (registerServiceImpl(guest) != null) {
onServiceAdded(guest);
}
@@ -920,9 +923,9 @@
public static class UserProfiles {
// Profiles of the current user.
- private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
+ private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
- public void updateCache(Context context) {
+ public void updateCache(@NonNull Context context) {
UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
if (userManager != null) {
int currentUserId = ActivityManager.getCurrentUser();
@@ -954,12 +957,12 @@
}
}
- protected static class Config {
- String caption;
- String serviceInterface;
- String secureSettingName;
- String bindPermission;
- String settingsAction;
- int clientLabel;
+ public static class Config {
+ public String caption;
+ public String serviceInterface;
+ public String secureSettingName;
+ public String bindPermission;
+ public String settingsAction;
+ public int clientLabel;
}
}
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..24ffe1f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -16,21 +16,21 @@
package com.android.server.notification;
-import static android.service.notification.NotificationAssistantService.REASON_APP_CANCEL;
-import static android.service.notification.NotificationAssistantService.REASON_APP_CANCEL_ALL;
-import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CANCEL;
-import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CANCEL_ALL;
-import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CLICK;
-import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_ERROR;
-import static android.service.notification.NotificationAssistantService.REASON_GROUP_OPTIMIZATION;
-import static android.service.notification.NotificationAssistantService.REASON_GROUP_SUMMARY_CANCELED;
-import static android.service.notification.NotificationAssistantService.REASON_LISTENER_CANCEL;
-import static android.service.notification.NotificationAssistantService.REASON_LISTENER_CANCEL_ALL;
-import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_BANNED;
-import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_CHANGED;
-import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_SUSPENDED;
-import static android.service.notification.NotificationAssistantService.REASON_PROFILE_TURNED_OFF;
-import static android.service.notification.NotificationAssistantService.REASON_USER_STOPPED;
+import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL;
+import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL_ALL;
+import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL;
+import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL_ALL;
+import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CLICK;
+import static android.service.notification.NotificationRankerService.REASON_DELEGATE_ERROR;
+import static android.service.notification.NotificationRankerService.REASON_GROUP_OPTIMIZATION;
+import static android.service.notification.NotificationRankerService.REASON_GROUP_SUMMARY_CANCELED;
+import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL;
+import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL_ALL;
+import static android.service.notification.NotificationRankerService.REASON_PACKAGE_BANNED;
+import static android.service.notification.NotificationRankerService.REASON_PACKAGE_CHANGED;
+import static android.service.notification.NotificationRankerService.REASON_PACKAGE_SUSPENDED;
+import static android.service.notification.NotificationRankerService.REASON_PROFILE_TURNED_OFF;
+import static android.service.notification.NotificationRankerService.REASON_USER_STOPPED;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
@@ -100,7 +100,7 @@
import android.service.notification.IConditionProvider;
import android.service.notification.INotificationListener;
import android.service.notification.IStatusBarNotificationHolder;
-import android.service.notification.NotificationAssistantService;
+import android.service.notification.NotificationRankerService;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationRankingUpdate;
import android.service.notification.StatusBarNotification;
@@ -128,10 +128,9 @@
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
import com.android.server.notification.ManagedServices.ManagedServiceInfo;
-import com.android.server.notification.ManagedServices.UserProfiles;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.vr.VrManagerInternal;
-import com.android.server.vr.VrStateListener;
+import com.android.server.notification.ManagedServices.UserProfiles;
import libcore.io.IoUtils;
@@ -220,14 +219,11 @@
StatusBarManagerInternal mStatusBar;
Vibrator mVibrator;
private VrManagerInternal mVrManagerInternal;
- private final NotificationVrListener mVrListener = new NotificationVrListener();
final IBinder mForegroundToken = new Binder();
private WorkerHandler mHandler;
private final HandlerThread mRankingThread = new HandlerThread("ranker",
Process.THREAD_PRIORITY_BACKGROUND);
- private final HandlerThread mAssistantThread = new HandlerThread("assistant",
- Process.THREAD_PRIORITY_BACKGROUND);
private Light mNotificationLight;
Light mAttentionLight;
@@ -293,14 +289,13 @@
private final UserProfiles mUserProfiles = new UserProfiles();
private NotificationListeners mListeners;
- private NotificationAssistant mAssistant;
+ private NotificationRanker mRankerServices;
private ConditionProviders mConditionProviders;
private NotificationUsageStats mUsageStats;
private static final int MY_UID = Process.myUid();
private static final int MY_PID = Process.myPid();
private RankingHandler mRankingHandler;
- private Handler mAssistantHandler;
private static class Archive {
final int mBufferSize;
@@ -758,7 +753,7 @@
}
}
mListeners.onPackagesChanged(queryReplace, pkgList);
- mAssistant.onPackagesChanged(queryReplace, pkgList);
+ mRankerServices.onPackagesChanged(queryReplace, pkgList);
mConditionProviders.onPackagesChanged(queryReplace, pkgList);
mRankingHelper.onPackagesChanged(queryReplace, pkgList);
}
@@ -807,7 +802,7 @@
// Refresh managed services
mConditionProviders.onUserSwitched(user);
mListeners.onUserSwitched(user);
- mAssistant.onUserSwitched(user);
+ mRankerServices.onUserSwitched(user);
mZenModeHelper.onUserSwitched(user);
} else if (action.equals(Intent.ACTION_USER_ADDED)) {
mUserProfiles.updateCache(context);
@@ -818,7 +813,7 @@
final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
mConditionProviders.onUserUnlocked(user);
mListeners.onUserUnlocked(user);
- mAssistant.onUserUnlocked(user);
+ mRankerServices.onUserUnlocked(user);
mZenModeHelper.onUserUnlocked(user);
}
}
@@ -856,14 +851,6 @@
}
}
- private final class NotificationVrListener extends VrStateListener {
- @Override
- public void onVrStateChanged(final boolean enabled) {
- mListeners.setCategoryState(NotificationListenerService.CATEGORY_VR_NOTIFICATIONS,
- enabled);
- }
- }
-
private SettingsObserver mSettingsObserver;
private ZenModeHelper mZenModeHelper;
@@ -902,7 +889,6 @@
mHandler = new WorkerHandler();
mRankingThread.start();
- mAssistantThread.start();
String[] extractorNames;
try {
extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
@@ -911,7 +897,6 @@
}
mUsageStats = new NotificationUsageStats(getContext());
mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
- mAssistantHandler = new Handler(mAssistantThread.getLooper());
mRankingHelper = new RankingHelper(getContext(),
mRankingHandler,
mUsageStats,
@@ -947,7 +932,7 @@
importOldBlockDb();
mListeners = new NotificationListeners();
- mAssistant = new NotificationAssistant();
+ mRankerServices = new NotificationRanker();
mStatusBar = getLocalService(StatusBarManagerInternal.class);
mStatusBar.setNotificationDelegate(mNotificationDelegate);
@@ -1064,14 +1049,13 @@
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
mVrManagerInternal = getLocalService(VrManagerInternal.class);
- mVrManagerInternal.registerListener(mVrListener);
mZenModeHelper.onSystemReady();
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
// This observer will force an update when observe is called, causing us to
// bind to listener services.
mSettingsObserver.observe();
mListeners.onBootPhaseAppsCanStart();
- mAssistant.onBootPhaseAppsCanStart();
+ mRankerServices.onBootPhaseAppsCanStart();
mConditionProviders.onBootPhaseAppsCanStart();
}
}
@@ -1320,7 +1304,7 @@
@Override
public int getImportance(String pkg, int uid) {
- checkCallerIsSystem();
+ enforceSystemOrSystemUI("Caller not system or systemui");
return mRankingHelper.getImportance(pkg, uid);
}
@@ -1426,17 +1410,30 @@
*/
@Override
public void registerListener(final INotificationListener listener,
- final ComponentName component, final int userid) {
+ final ComponentName component, final int userid, boolean asRanker) {
enforceSystemOrSystemUI("INotificationManager.registerListener");
- mListeners.registerService(listener, component, userid);
+ if (asRanker) {
+ mRankerServices.registerService(listener, component, userid);
+ } else {
+ mListeners.registerService(listener, component, userid);
+ }
}
/**
* Remove a listener binder directly
*/
@Override
- public void unregisterListener(INotificationListener listener, int userid) {
- mListeners.unregisterService(listener, userid);
+ public void unregisterListener(INotificationListener token, int userid) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ if(mRankerServices.checkServiceTokenLocked(token) != null) {
+ mRankerServices.unregisterService(token, userid);
+ } else {
+ mListeners.unregisterService(token, userid);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
/**
@@ -1489,8 +1486,8 @@
checkCallerIsSystemOrSameApp(component.getPackageName());
long identity = Binder.clearCallingIdentity();
try {
- ManagedServices manager = mAssistant.isComponentEnabledForCurrentProfiles(component)
- ? mAssistant
+ ManagedServices manager = mRankerServices.isComponentEnabledForCurrentProfiles(component)
+ ? mRankerServices
: mListeners;
manager.setComponentState(component, true);
} finally {
@@ -1983,7 +1980,7 @@
}
@Override
- public void setImportanceFromAssistant(INotificationListener token, String key,
+ public void setImportanceFromRankerService(INotificationListener token, String key,
int importance, CharSequence explanation) throws RemoteException {
if (importance == IMPORTANCE_NONE) {
throw new IllegalArgumentException("blocking not allowed: key=" + key);
@@ -1991,7 +1988,7 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationList) {
- mAssistant.checkServiceTokenLocked(token);
+ mRankerServices.checkServiceTokenLocked(token);
NotificationRecord n = mNotificationsByKey.get(key);
n.setImportance(importance, explanation);
mRankingHandler.requestSort();
@@ -2141,8 +2138,8 @@
pw.print(listener.component);
}
pw.println(')');
- pw.println("\n Notification assistant:");
- mAssistant.dump(pw, filter);
+ pw.println("\n Notification ranker services:");
+ mRankerServices.dump(pw, filter);
}
pw.println("\n Policy access:");
pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess);
@@ -2369,9 +2366,9 @@
}
}
- // tell the assistant about the notification
- if (mAssistant.isEnabled()) {
- mAssistant.onNotificationEnqueued(r);
+ // tell the ranker service about the notification
+ if (mRankerServices.isEnabled()) {
+ mRankerServices.onNotificationEnqueued(r);
// TODO delay the code below here for 100ms or until there is an answer
}
@@ -3488,21 +3485,21 @@
}
}
- public class NotificationAssistant extends ManagedServices {
+ public class NotificationRanker extends ManagedServices {
- public NotificationAssistant() {
+ public NotificationRanker() {
super(getContext(), mHandler, mNotificationList, mUserProfiles);
}
@Override
protected Config getConfig() {
Config c = new Config();
- c.caption = "notification assistant";
- c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
- c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
- c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
+ c.caption = "notification ranker service";
+ c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE;
+ c.secureSettingName = null;
+ c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE;
c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
- c.clientLabel = R.string.notification_assistant_binding_label;
+ c.clientLabel = R.string.notification_ranker_binding_label;
return c;
}
@@ -3530,10 +3527,10 @@
final StatusBarNotification sbn = r.sbn;
TrimCache trimCache = new TrimCache(sbn);
- // mServices is the list inside ManagedServices of all the assistants,
+ // mServices is the list inside ManagedServices of all the rankers,
// There should be only one, but it's a list, so while we enforce
// singularity elsewhere, we keep it general here, to avoid surprises.
- for (final ManagedServiceInfo info : NotificationAssistant.this.mServices) {
+ for (final ManagedServiceInfo info : NotificationRanker.this.mServices) {
boolean sbnVisible = isVisibleToListener(sbn, info);
if (!sbnVisible) {
continue;
@@ -3542,7 +3539,7 @@
final int importance = r.getImportance();
final boolean fromUser = r.isImportanceFromUser();
final StatusBarNotification sbnToPost = trimCache.ForListener(info);
- mAssistantHandler.post(new Runnable() {
+ mHandler.post(new Runnable() {
@Override
public void run() {
notifyEnqueued(info, sbnToPost, importance, fromUser);
@@ -3553,12 +3550,12 @@
private void notifyEnqueued(final ManagedServiceInfo info,
final StatusBarNotification sbn, int importance, boolean fromUser) {
- final INotificationListener assistant = (INotificationListener) info.service;
+ final INotificationListener ranker = (INotificationListener) info.service;
StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
try {
- assistant.onNotificationEnqueued(sbnHolder, importance, fromUser);
+ ranker.onNotificationEnqueued(sbnHolder, importance, fromUser);
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
+ Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex);
}
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index d6b59f9..27c8293 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -31,6 +31,7 @@
import android.net.Uri;
import android.os.Build;
import android.os.UserHandle;
+import android.print.PrintManager;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
import android.provider.MediaStore;
@@ -579,7 +580,7 @@
// Print Spooler
PackageParser.Package printSpoolerPackage = getSystemPackageLPr(
- "com.android.printspooler");
+ PrintManager.PRINT_SPOOLER_PACKAGE_NAME);
if (printSpoolerPackage != null
&& doesPackageSupportRuntimePermissions(printSpoolerPackage)) {
grantRuntimePermissionsLPw(printSpoolerPackage, LOCATION_PERMISSIONS, true, userId);
@@ -714,7 +715,8 @@
private PackageParser.Package getDefaultSystemHandlerServicePackageLPr(
Intent intent, int userId) {
List<ResolveInfo> handlers = mService.queryIntentServices(intent,
- intent.resolveType(mService.mContext.getContentResolver()), DEFAULT_FLAGS, userId);
+ intent.resolveType(mService.mContext.getContentResolver()), DEFAULT_FLAGS, userId)
+ .getList();
if (handlers == null) {
return null;
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 1476e6e..206a143 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -166,6 +166,10 @@
mInstaller.execute("rmpackagedir", packageDir);
}
+ public void rmProfiles(String pkgName) throws InstallerException {
+ mInstaller.execute("rmprofiles", pkgName);
+ }
+
public void createUserConfig(int userid) throws InstallerException {
mInstaller.execute("mkuserconfig", userid);
}
@@ -203,6 +207,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..561682c 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,38 +151,46 @@
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);
}
-
Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
+ pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
+ " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
@@ -226,15 +213,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 +295,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 7f49765..e180e050 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -62,7 +62,9 @@
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE;
import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
+import static android.content.pm.PackageManager.MATCH_ENCRYPTION_UNAWARE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.MOVE_FAILED_DEVICE_ADMIN;
@@ -101,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;
@@ -172,7 +175,6 @@
import android.os.Message;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -358,6 +360,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;
@@ -497,6 +500,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>>();
@@ -637,9 +643,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;
@@ -1426,19 +1429,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
@@ -1633,11 +1638,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
@@ -2159,10 +2165,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,
@@ -2556,7 +2564,7 @@
private @Nullable String getRequiredButNotReallyRequiredVerifierLPr() {
final Intent intent = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
- final List<ResolveInfo> matches = queryIntentReceivers(intent, PACKAGE_MIME_TYPE,
+ final List<ResolveInfo> matches = queryIntentReceiversInternal(intent, PACKAGE_MIME_TYPE,
MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
if (matches.size() == 1) {
return matches.get(0).getComponentInfo().packageName;
@@ -2571,7 +2579,7 @@
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
- final List<ResolveInfo> matches = queryIntentActivities(intent, PACKAGE_MIME_TYPE,
+ final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, PACKAGE_MIME_TYPE,
MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
if (matches.size() == 1) {
return matches.get(0).getComponentInfo().packageName;
@@ -2583,7 +2591,7 @@
private @NonNull ComponentName getIntentFilterVerifierComponentNameLPr() {
final Intent intent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
- final List<ResolveInfo> matches = queryIntentReceivers(intent, PACKAGE_MIME_TYPE,
+ final List<ResolveInfo> matches = queryIntentReceiversInternal(intent, PACKAGE_MIME_TYPE,
MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
ResolveInfo best = null;
final int N = matches.size();
@@ -2618,7 +2626,7 @@
}
final Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE);
- final List<ResolveInfo> resolvers = queryIntentServices(resolverIntent, null,
+ final List<ResolveInfo> resolvers = queryIntentServicesInternal(resolverIntent, null,
MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
final int N = resolvers.size();
@@ -2663,7 +2671,7 @@
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
- final List<ResolveInfo> matches = queryIntentActivities(intent, PACKAGE_MIME_TYPE,
+ final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, PACKAGE_MIME_TYPE,
MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
if (matches.size() == 0) {
return null;
@@ -2758,7 +2766,7 @@
private List<String> resolveAllBrowserApps(int userId) {
// Resolve the canonical browser intent and check that the handleAllWebDataURI boolean is set
- List<ResolveInfo> list = queryIntentActivities(sBrowserIntent, null,
+ List<ResolveInfo> list = queryIntentActivitiesInternal(sBrowserIntent, null,
PackageManager.MATCH_ALL, userId);
final int count = list.size();
@@ -2778,7 +2786,7 @@
}
private boolean packageIsBrowser(String packageName, int userId) {
- List<ResolveInfo> list = queryIntentActivities(sBrowserIntent, null,
+ List<ResolveInfo> list = queryIntentActivitiesInternal(sBrowserIntent, null,
PackageManager.MATCH_ALL, userId);
final int N = list.size();
for (int i = 0; i < N; i++) {
@@ -3027,9 +3035,15 @@
}
@Override
- public List<PermissionInfo> queryPermissionsByGroup(String group, int flags) {
+ public @Nullable ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String group,
+ int flags) {
// reader
synchronized (mPackages) {
+ if (group != null && !mPermissionGroups.containsKey(group)) {
+ // This is thrown as NameNotFoundException
+ return null;
+ }
+
ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
for (BasePermission p : mSettings.mPermissions.values()) {
if (group == null) {
@@ -3042,11 +3056,7 @@
}
}
}
-
- if (out.size() > 0) {
- return out;
- }
- return mPermissionGroups.containsKey(group) ? out : null;
+ return new ParceledListSlice<>(out);
}
}
@@ -3060,7 +3070,7 @@
}
@Override
- public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
+ public @NonNull ParceledListSlice<PermissionGroupInfo> getAllPermissionGroups(int flags) {
// reader
synchronized (mPackages) {
final int N = mPermissionGroups.size();
@@ -3069,7 +3079,7 @@
for (PackageParser.PermissionGroup pg : mPermissionGroups.values()) {
out.add(PackageParser.generatePermissionGroupInfo(pg, flags));
}
- return out;
+ return new ParceledListSlice<>(out);
}
}
@@ -3467,22 +3477,17 @@
}
@Override
- public FeatureInfo[] getSystemAvailableFeatures() {
- Collection<FeatureInfo> featSet;
+ public @NonNull ParceledListSlice<FeatureInfo> getSystemAvailableFeatures() {
synchronized (mPackages) {
- featSet = mAvailableFeatures.values();
- int size = featSet.size();
- if (size > 0) {
- FeatureInfo[] features = new FeatureInfo[size+1];
- featSet.toArray(features);
- FeatureInfo fi = new FeatureInfo();
- fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
- FeatureInfo.GL_ES_VERSION_UNDEFINED);
- features[size] = fi;
- return features;
- }
+ final ArrayList<FeatureInfo> res = new ArrayList<>(mAvailableFeatures.values());
+
+ final FeatureInfo fi = new FeatureInfo();
+ fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
+ FeatureInfo.GL_ES_VERSION_UNDEFINED);
+ res.add(fi);
+
+ return new ParceledListSlice<>(res);
}
- return null;
}
@Override
@@ -4232,7 +4237,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;
}
}
@@ -4437,6 +4443,13 @@
}
@Override
+ public List<String> getAllPackages() {
+ synchronized (mPackages) {
+ return new ArrayList<String>(mPackages.keySet());
+ }
+ }
+
+ @Override
public String[] getPackagesForUid(int uid) {
uid = UserHandle.getAppId(uid);
// reader
@@ -4561,7 +4574,8 @@
flags = updateFlagsForResolve(flags, userId, intent);
enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */, "resolve intent");
- List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
+ final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
+ userId);
final ResolveInfo bestChoice =
chooseBestActivity(intent, resolvedType, flags, query, userId);
@@ -4593,7 +4607,8 @@
filter.dump(new PrintStreamPrinter(System.out), " ");
}
intent.setComponent(null);
- List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
+ final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
+ userId);
// Find any earlier preferred or last chosen entries and nuke them
findPreferredActivity(intent, resolvedType,
flags, query, 0, false, true, false, userId);
@@ -4606,7 +4621,8 @@
public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) {
final int userId = UserHandle.getCallingUserId();
if (DEBUG_PREFERRED) Log.v(TAG, "Querying last chosen activity for " + intent);
- List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
+ final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
+ userId);
return findPreferredActivity(intent, resolvedType, flags, query, 0,
false, false, false, userId);
}
@@ -5017,7 +5033,13 @@
}
@Override
- public List<ResolveInfo> queryIntentActivities(Intent intent,
+ public @NonNull ParceledListSlice<ResolveInfo> queryIntentActivities(Intent intent,
+ String resolvedType, int flags, int userId) {
+ return new ParceledListSlice<>(
+ queryIntentActivitiesInternal(intent, resolvedType, flags, userId));
+ }
+
+ private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
flags = updateFlagsForResolve(flags, userId, intent);
@@ -5508,7 +5530,14 @@
}
@Override
- public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
+ public @NonNull ParceledListSlice<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
+ Intent[] specifics, String[] specificTypes, Intent intent,
+ String resolvedType, int flags, int userId) {
+ return new ParceledListSlice<>(queryIntentActivityOptionsInternal(caller, specifics,
+ specificTypes, intent, resolvedType, flags, userId));
+ }
+
+ private @NonNull List<ResolveInfo> queryIntentActivityOptionsInternal(ComponentName caller,
Intent[] specifics, String[] specificTypes, Intent intent,
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
@@ -5518,7 +5547,7 @@
"query intent activity options");
final String resultsAction = intent.getAction();
- List<ResolveInfo> results = queryIntentActivities(intent, resolvedType, flags
+ final List<ResolveInfo> results = queryIntentActivitiesInternal(intent, resolvedType, flags
| PackageManager.GET_RESOLVED_FILTER, userId);
if (DEBUG_INTENT_MATCHING) {
@@ -5683,8 +5712,14 @@
}
@Override
- public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags,
- int userId) {
+ public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
+ String resolvedType, int flags, int userId) {
+ return new ParceledListSlice<>(
+ queryIntentReceiversInternal(intent, resolvedType, flags, userId));
+ }
+
+ private @NonNull List<ResolveInfo> queryIntentReceiversInternal(Intent intent,
+ String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
flags = updateFlagsForResolve(flags, userId, intent);
ComponentName comp = intent.getComponent();
@@ -5716,7 +5751,7 @@
return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers,
userId);
}
- return null;
+ return Collections.emptyList();
}
}
@@ -5724,7 +5759,7 @@
public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
flags = updateFlagsForResolve(flags, userId, intent);
- List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags, userId);
+ List<ResolveInfo> query = queryIntentServicesInternal(intent, resolvedType, flags, userId);
if (query != null) {
if (query.size() >= 1) {
// If there is more than one service with the same priority,
@@ -5736,8 +5771,14 @@
}
@Override
- public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags,
- int userId) {
+ public @NonNull ParceledListSlice<ResolveInfo> queryIntentServices(Intent intent,
+ String resolvedType, int flags, int userId) {
+ return new ParceledListSlice<>(
+ queryIntentServicesInternal(intent, resolvedType, flags, userId));
+ }
+
+ private @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
+ String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
flags = updateFlagsForResolve(flags, userId, intent);
ComponentName comp = intent.getComponent();
@@ -5769,12 +5810,18 @@
return mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services,
userId);
}
- return null;
+ return Collections.emptyList();
}
}
@Override
- public List<ResolveInfo> queryIntentContentProviders(
+ public @NonNull ParceledListSlice<ResolveInfo> queryIntentContentProviders(Intent intent,
+ String resolvedType, int flags, int userId) {
+ return new ParceledListSlice<>(
+ queryIntentContentProvidersInternal(intent, resolvedType, flags, userId));
+ }
+
+ private @NonNull List<ResolveInfo> queryIntentContentProvidersInternal(
Intent intent, String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
flags = updateFlagsForResolve(flags, userId, intent);
@@ -5807,7 +5854,7 @@
return mProviders.queryIntentForPackage(
intent, resolvedType, flags, pkg.providers, userId);
}
- return null;
+ return Collections.emptyList();
}
}
@@ -6063,7 +6110,12 @@
&& UserHandle.getAppId(Binder.getCallingUid()) == pkg.applicationInfo.uid;
}
- public List<ApplicationInfo> getPersistentApplications(int flags) {
+ @Override
+ public @NonNull ParceledListSlice<ApplicationInfo> getPersistentApplications(int flags) {
+ return new ParceledListSlice<>(getPersistentApplicationsInternal(flags));
+ }
+
+ private @NonNull List<ApplicationInfo> getPersistentApplicationsInternal(int flags) {
final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
// reader
@@ -6072,9 +6124,16 @@
final int userId = UserHandle.getCallingUserId();
while (i.hasNext()) {
final PackageParser.Package p = i.next();
- if (p.applicationInfo != null
- && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0
- && (!mSafeMode || isSystemApp(p))) {
+ if (p.applicationInfo == null) continue;
+
+ final boolean matchesUnaware = ((flags & MATCH_ENCRYPTION_UNAWARE) != 0)
+ && !p.applicationInfo.isEncryptionAware();
+ final boolean matchesAware = ((flags & MATCH_ENCRYPTION_AWARE) != 0)
+ && p.applicationInfo.isEncryptionAware();
+
+ if ((p.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0
+ && (!mSafeMode || isSystemApp(p))
+ && (matchesUnaware || matchesAware)) {
PackageSetting ps = mSettings.mPackages.get(p.packageName);
if (ps != null) {
ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
@@ -6138,11 +6197,11 @@
}
@Override
- public ParceledListSlice<ProviderInfo> queryContentProviders(String processName,
+ public @NonNull ParceledListSlice<ProviderInfo> queryContentProviders(String processName,
int uid, int flags) {
final int userId = processName != null ? UserHandle.getUserId(uid)
: UserHandle.getCallingUserId();
- if (!sUserManager.exists(userId)) return null;
+ if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
flags = updateFlagsForComponent(flags, userId, processName);
ArrayList<ProviderInfo> finalList = null;
@@ -6174,7 +6233,7 @@
return new ParceledListSlice<ProviderInfo>(finalList);
}
- return null;
+ return ParceledListSlice.emptyList();
}
@Override
@@ -6187,10 +6246,14 @@
}
@Override
- public List<InstrumentationInfo> queryInstrumentation(String targetPackage,
+ public @NonNull ParceledListSlice<InstrumentationInfo> queryInstrumentation(
+ String targetPackage, int flags) {
+ return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags));
+ }
+
+ private @NonNull List<InstrumentationInfo> queryInstrumentationInternal(String targetPackage,
int flags) {
- ArrayList<InstrumentationInfo> finalList =
- new ArrayList<InstrumentationInfo>();
+ ArrayList<InstrumentationInfo> finalList = new ArrayList<InstrumentationInfo>();
// reader
synchronized (mPackages) {
@@ -6828,7 +6891,7 @@
// Extract pacakges only if profile-guided compilation is enabled because
// otherwise BackgroundDexOptService will not dexopt them later.
- if (!mUseJitProfiles || !isUpgrade()) {
+ if (!isUpgrade()) {
return;
}
@@ -6910,10 +6973,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 {
@@ -7894,13 +7953,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.
@@ -10589,7 +10652,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) {
@@ -11065,21 +11128,22 @@
}
@Override
- public List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName) {
+ public @NonNull ParceledListSlice<IntentFilterVerificationInfo> getIntentFilterVerifications(
+ String packageName) {
synchronized (mPackages) {
- return mSettings.getIntentFilterVerificationsLPr(packageName);
+ return new ParceledListSlice<>(mSettings.getIntentFilterVerificationsLPr(packageName));
}
}
@Override
- public List<IntentFilter> getAllIntentFilters(String packageName) {
+ public @NonNull ParceledListSlice<IntentFilter> getAllIntentFilters(String packageName) {
if (TextUtils.isEmpty(packageName)) {
- return Collections.<IntentFilter>emptyList();
+ return ParceledListSlice.emptyList();
}
synchronized (mPackages) {
PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null || pkg.activities == null) {
- return Collections.<IntentFilter>emptyList();
+ return ParceledListSlice.emptyList();
}
final int count = pkg.activities.size();
ArrayList<IntentFilter> result = new ArrayList<>();
@@ -11089,7 +11153,7 @@
result.addAll(activity.intents);
}
}
- return result;
+ return new ParceledListSlice<>(result);
}
}
@@ -11815,7 +11879,7 @@
verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// Query all live verifiers based on current user state
- final List<ResolveInfo> receivers = queryIntentReceivers(verification,
+ final List<ResolveInfo> receivers = queryIntentReceiversInternal(verification,
PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier());
if (DEBUG_VERIFY) {
@@ -13072,6 +13136,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) {
@@ -13081,12 +13154,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");
@@ -13112,6 +13189,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) {
@@ -13124,7 +13222,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);
}
@@ -13577,6 +13675,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);
@@ -13843,21 +13944,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;
}
}
@@ -14301,7 +14398,8 @@
}
if (res) {
- info.sendPackageRemovedBroadcasts();
+ final boolean killApp = (flags & PackageManager.INSTALL_DONT_KILL_APP) == 0;
+ info.sendPackageRemovedBroadcasts(killApp);
info.sendSystemPackageUpdatedBroadcasts();
info.sendSystemPackageAppearedBroadcasts();
}
@@ -14333,12 +14431,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);
}
}
@@ -14380,10 +14478,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);
}
@@ -14874,7 +14973,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);
}
@@ -15052,12 +15154,29 @@
}
@Override
+ public void clearApplicationProfileData(String packageName) {
+ enforceSystemOrRoot("Only the system can clear all profile data");
+ try {
+ mInstaller.rmProfiles(packageName);
+ } catch (InstallerException ex) {
+ Log.e(TAG, "Could not clear profile data of package " + packageName);
+ }
+ }
+
+ @Override
public void clearApplicationUserData(final String packageName,
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() {
@@ -15069,8 +15188,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();
}
@@ -15469,22 +15588,6 @@
return true;
}
-
- @Override
- public void addPackageToPreferred(String packageName) {
- Slog.w(TAG, "addPackageToPreferred: this is now a no-op");
- }
-
- @Override
- public void removePackageFromPreferred(String packageName) {
- Slog.w(TAG, "removePackageFromPreferred: this is now a no-op");
- }
-
- @Override
- public List<PackageInfo> getPreferredPackages(int flags) {
- return new ArrayList<PackageInfo>();
- }
-
private int getUidTargetSdkVersionLockedLPr(int uid) {
Object obj = mSettings.getUserIdLPr(uid);
if (obj instanceof SharedUserSetting) {
@@ -16337,7 +16440,7 @@
intent.addCategory(Intent.CATEGORY_HOME);
final int callingUserId = UserHandle.getCallingUserId();
- List<ResolveInfo> list = queryIntentActivities(intent, null,
+ List<ResolveInfo> list = queryIntentActivitiesInternal(intent, null,
PackageManager.GET_META_DATA, callingUserId);
ResolveInfo preferred = findPreferredActivity(intent, null, 0, list, 0,
true, false, false, callingUserId);
@@ -17333,8 +17436,9 @@
}
private String dumpDomainString(String packageName) {
- List<IntentFilterVerificationInfo> iviList = getIntentFilterVerifications(packageName);
- List<IntentFilter> filters = getAllIntentFilters(packageName);
+ List<IntentFilterVerificationInfo> iviList = getIntentFilterVerifications(packageName)
+ .getList();
+ List<IntentFilter> filters = getAllIntentFilters(packageName).getList();
ArraySet<String> result = new ArraySet<>();
if (iviList.size() > 0) {
@@ -19123,6 +19227,11 @@
return permissionsState.isPermissionReviewRequired(userId);
}
}
+
+ @Override
+ public ApplicationInfo getApplicationInfo(String packageName, int userId) {
+ return PackageManagerService.this.getApplicationInfo(packageName, 0 /*flags*/, userId);
+ }
}
@Override
@@ -19150,4 +19259,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/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index a3ac514..f79d6ee 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -16,13 +16,15 @@
package com.android.server.pm;
+import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
+import static com.android.server.pm.PackageManagerService.TAG;
+
import android.app.AppGlobals;
import android.content.Intent;
import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.Package;
import android.content.pm.ResolveInfo;
-import android.os.UserHandle;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Log;
@@ -35,9 +37,6 @@
import java.util.List;
import java.util.Set;
-import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
-import static com.android.server.pm.PackageManagerService.TAG;
-
/**
* Class containing helper methods for the PackageManagerService.
*
@@ -49,7 +48,8 @@
private static ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
List<ResolveInfo> ris = null;
try {
- ris = AppGlobals.getPackageManager().queryIntentReceivers(intent, null, 0, userId);
+ ris = AppGlobals.getPackageManager().queryIntentReceivers(intent, null, 0, userId)
+ .getList();
} catch (RemoteException e) {
}
ArraySet<String> pkgNames = new ArraySet<String>();
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index abee007..28d34a8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -233,17 +233,30 @@
boolean useJitProfiles = false;
boolean extractOnly = false;
boolean forceCompilation = false;
+ boolean allPackages = false;
+ boolean clearProfileData = false;
String compilationMode = "default";
String opt;
while ((opt = getNextOption()) != null) {
switch (opt) {
- case "-m":
- compilationMode = getNextArgRequired();
+ case "-a":
+ allPackages = true;
+ break;
+ case "-c":
+ clearProfileData = true;
break;
case "-f":
forceCompilation = true;
break;
+ case "-m":
+ compilationMode = getNextArgRequired();
+ break;
+ case "--reset":
+ forceCompilation = true;
+ clearProfileData = true;
+ compilationMode = "extract";
+ break;
default:
pw.println("Error: Unknown option: " + opt);
return 1;
@@ -255,7 +268,7 @@
useJitProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
extractOnly = false;
break;
- case "all":
+ case "full":
useJitProfiles = false;
extractOnly = false;
break;
@@ -272,19 +285,49 @@
return 1;
}
- String packageName = getNextArg();
- if (packageName == null) {
- pw.println("Error: package name not specified");
- return 1;
+ List<String> packageNames = null;
+ if (allPackages) {
+ packageNames = mInterface.getAllPackages();
+ } else {
+ String packageName = getNextArg();
+ if (packageName == null) {
+ pw.println("Error: package name not specified");
+ return 1;
+ }
+ packageNames = Collections.singletonList(packageName);
}
- boolean success = mInterface.performDexOpt(packageName, null /* instructionSet */,
- useJitProfiles, extractOnly, forceCompilation);
- if (success) {
+ List<String> failedPackages = new ArrayList<>();
+ for (String packageName : packageNames) {
+ if (clearProfileData) {
+ mInterface.clearApplicationProfileData(packageName);
+ }
+
+ boolean result = mInterface.performDexOpt(packageName, null /* instructionSet */,
+ useJitProfiles, extractOnly, forceCompilation);
+ if (!result) {
+ failedPackages.add(packageName);
+ }
+ }
+
+ if (failedPackages.isEmpty()) {
pw.println("Success");
return 0;
+ } else if (failedPackages.size() == 1) {
+ pw.println("Failure: package " + failedPackages.get(0) + " could not be compiled");
+ return 1;
} else {
- pw.println("Failure: package " + packageName + " could not be compiled");
+ pw.print("Failure: the following packages could not be compiled: ");
+ boolean is_first = true;
+ for (String packageName : failedPackages) {
+ if (is_first) {
+ is_first = false;
+ } else {
+ pw.print(", ");
+ }
+ pw.print(packageName);
+ }
+ pw.println();
return 1;
}
}
@@ -317,11 +360,7 @@
private int runListFeatures() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
- final List<FeatureInfo> list = new ArrayList<FeatureInfo>();
- final FeatureInfo[] rawList = mInterface.getSystemAvailableFeatures();
- for (int i=0; i<rawList.length; i++) {
- list.add(rawList[i]);
- }
+ final List<FeatureInfo> list = mInterface.getSystemAvailableFeatures().getList();
// sort by name
Collections.sort(list, new Comparator<FeatureInfo>() {
@@ -380,7 +419,7 @@
}
final List<InstrumentationInfo> list =
- mInterface.queryInstrumentation(targetPackage, 0 /*flags*/);
+ mInterface.queryInstrumentation(targetPackage, 0 /*flags*/).getList();
// sort by target package
Collections.sort(list, new Comparator<InstrumentationInfo>() {
@@ -521,7 +560,7 @@
private int runListPermissionGroups() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
- final List<PermissionGroupInfo> pgs = mInterface.getAllPermissionGroups(0);
+ final List<PermissionGroupInfo> pgs = mInterface.getAllPermissionGroups(0).getList();
final int count = pgs.size();
for (int p = 0; p < count ; p++) {
@@ -568,7 +607,7 @@
final ArrayList<String> groupList = new ArrayList<String>();
if (groups) {
final List<PermissionGroupInfo> infos =
- mInterface.getAllPermissionGroups(0 /*flags*/);
+ mInterface.getAllPermissionGroups(0 /*flags*/).getList();
final int count = infos.size();
for (int i = 0; i < count; i++) {
groupList.add(infos.get(i).name);
@@ -718,7 +757,7 @@
}
try {
List<ResolveInfo> result = mInterface.queryIntentActivities(intent, null, 0,
- mTargetUser);
+ mTargetUser).getList();
PrintWriter pw = getOutPrintWriter();
if (result == null || result.size() <= 0) {
pw.println("No activities found");
@@ -745,7 +784,7 @@
}
try {
List<ResolveInfo> result = mInterface.queryIntentServices(intent, null, 0,
- mTargetUser);
+ mTargetUser).getList();
PrintWriter pw = getOutPrintWriter();
if (result == null || result.size() <= 0) {
pw.println("No services found");
@@ -772,7 +811,7 @@
}
try {
List<ResolveInfo> result = mInterface.queryIntentReceivers(intent, null, 0,
- mTargetUser);
+ mTargetUser).getList();
PrintWriter pw = getOutPrintWriter();
if (result == null || result.size() <= 0) {
pw.println("No receivers found");
@@ -1051,7 +1090,7 @@
prefix = " ";
}
List<PermissionInfo> ps =
- mInterface.queryPermissionsByGroup(groupList.get(i), 0 /*flags*/);
+ mInterface.queryPermissionsByGroup(groupList.get(i), 0 /*flags*/).getList();
final int count = ps.size();
boolean first = true;
for (int p = 0 ; p < count ; p++) {
@@ -1139,12 +1178,17 @@
pw.println(" help");
pw.println(" Print this help text.");
pw.println("");
- pw.println(" compile [-m MODE] [-f] TARGET-PACKAGE");
- pw.println(" Trigger compilation of TARGET-PACKAGE.");
+ pw.println(" compile [-m MODE] [-f] [-c] [--reset] (-a | TARGET-PACKAGE)");
+ pw.println(" Trigger compilation of TARGET-PACKAGE or all packages if \"-a\".");
pw.println(" Options:");
- pw.println(" -m: select compilation mode");
- pw.println(" MODE can be one of \"default\", \"all\", \"profile\", and \"extract\"");
+ pw.println(" -a: compile all packages");
+ pw.println(" -c: clear profile data before compiling");
pw.println(" -f: force compilation even if not needed");
+ pw.println(" -m: select compilation mode");
+ pw.println(" MODE can be one of \"default\", \"full\", \"profile\"," +
+ " and \"extract\"");
+ pw.println(" --reset: restore package to its post-install state");
+ pw.println(" shorthand for \"-c -f -m extract\"");
pw.println(" list features");
pw.println(" Prints all features of the system.");
pw.println(" list instrumentation [-f] [TARGET-PACKAGE]");
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 1652185..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);
}
@@ -3049,7 +3048,7 @@
tmpPa.dump(new LogPrinter(Log.DEBUG, TAG), " ");
}
Intent intent = new Intent();
- int flags = 0;
+ int flags = PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
intent.setAction(tmpPa.getAction(0));
for (int i=0; i<tmpPa.countCategories(); i++) {
String cat = tmpPa.getCategory(i);
@@ -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..e51a2e1 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -57,6 +57,7 @@
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.CompatibilityInfo;
@@ -76,6 +77,7 @@
import android.media.RingtoneManager;
import android.media.session.MediaSessionLegacyHelper;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.FactoryTest;
@@ -535,6 +537,7 @@
boolean mForceStatusBar;
boolean mForceStatusBarFromKeyguard;
private boolean mForceStatusBarTransparent;
+ boolean mForceNavBarOpaque;
boolean mHideLockScreen;
boolean mForcingShowNavBar;
int mForcingShowNavBarLayer;
@@ -1715,6 +1718,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
@@ -2053,7 +2059,7 @@
// check if user has enabled this operation. SecurityException will be thrown if
// this app has not been allowed by the user
- final int mode = mAppOpsManager.checkOp(outAppOp[0], callingUid,
+ final int mode = mAppOpsManager.checkOpNoThrow(outAppOp[0], callingUid,
attrs.packageName);
switch (mode) {
case AppOpsManager.MODE_ALLOWED:
@@ -2062,6 +2068,17 @@
// actually be hidden in WindowManagerService
return WindowManagerGlobal.ADD_OKAY;
case AppOpsManager.MODE_ERRORED:
+ try {
+ ApplicationInfo appInfo = mContext.getPackageManager()
+ .getApplicationInfo(attrs.packageName,
+ UserHandle.getUserId(callingUid));
+ // Don't crash legacy apps
+ if (appInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+ return WindowManagerGlobal.ADD_OKAY;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ /* ignore */
+ }
return WindowManagerGlobal.ADD_PERMISSION_DENIED;
default:
// in the default mode, we will make a decision here based on
@@ -7080,6 +7097,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..91d8671 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -50,6 +50,7 @@
import android.os.WorkSource;
import android.provider.Settings;
import android.provider.Settings.Secure;
+import android.provider.Settings.SettingNotFoundException;
import android.service.dreams.DreamManagerInternal;
import android.util.EventLog;
import android.util.Slog;
@@ -57,9 +58,11 @@
import android.util.TimeUtils;
import android.view.Display;
import android.view.WindowManagerPolicy;
+
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 +257,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 +531,16 @@
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;
+
+ incrementBootCount();
}
}
}
@@ -750,7 +766,17 @@
mDirty |= DIRTY_SETTINGS;
}
- void updateLowPowerModeLocked() {
+ 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);
+ }
+ }
+
+ private void updateLowPowerModeLocked() {
if (mIsPowered && mLowPowerModeSetting) {
if (DEBUG_SPEW) {
Slog.d(TAG, "updateLowPowerModeLocked: powered, turning setting off");
@@ -767,7 +793,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)
@@ -2890,6 +2916,20 @@
return suspendBlocker;
}
+ private void incrementBootCount() {
+ synchronized (mLock) {
+ int count;
+ try {
+ count = Settings.Global.getInt(
+ getContext().getContentResolver(), Settings.Global.BOOT_COUNT);
+ } catch (SettingNotFoundException e) {
+ count = 0;
+ }
+ Settings.Global.putInt(
+ getContext().getContentResolver(), Settings.Global.BOOT_COUNT, count + 1);
+ }
+ }
+
private static WorkSource copyWorkSource(WorkSource workSource) {
return workSource != null ? new WorkSource(workSource) : null;
}
diff --git a/services/core/java/com/android/server/search/Searchables.java b/services/core/java/com/android/server/search/Searchables.java
index 0046fbb..6bacdfd 100644
--- a/services/core/java/com/android/server/search/Searchables.java
+++ b/services/core/java/com/android/server/search/Searchables.java
@@ -410,7 +410,7 @@
activities =
mPm.queryIntentActivities(intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- flags, mUserId);
+ flags, mUserId).getList();
} catch (RemoteException re) {
// Local call
}
diff --git a/services/core/java/com/android/server/utils/ManagedApplicationService.java b/services/core/java/com/android/server/utils/ManagedApplicationService.java
new file mode 100644
index 0000000..a645701
--- /dev/null
+++ b/services/core/java/com/android/server/utils/ManagedApplicationService.java
@@ -0,0 +1,220 @@
+/**
+ * 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.utils;
+
+import android.annotation.NonNull;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.IInterface;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import java.util.Objects;
+
+/**
+ * Manages the lifecycle of an application-provided service bound from system server.
+ *
+ * @hide
+ */
+public class ManagedApplicationService {
+ private final String TAG = getClass().getSimpleName();
+
+ private final Context mContext;
+ private final int mUserId;
+ private final ComponentName mComponent;
+ private final int mClientLabel;
+ private final String mSettingsAction;
+ private final BinderChecker mChecker;
+
+ private final DeathRecipient mDeathRecipient = new DeathRecipient() {
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ mBoundInterface = null;
+ }
+ }
+ };
+
+ private final Object mLock = new Object();
+
+ // State protected by mLock
+ private ServiceConnection mPendingConnection;
+ private ServiceConnection mConnection;
+ private IInterface mBoundInterface;
+
+
+ private ManagedApplicationService(final Context context, final ComponentName component,
+ final int userId, int clientLabel, String settingsAction,
+ BinderChecker binderChecker) {
+ mContext = context;
+ mComponent = component;
+ mUserId = userId;
+ mClientLabel = clientLabel;
+ mSettingsAction = settingsAction;
+ mChecker = binderChecker;
+ }
+
+ /**
+ * Implement to validate returned IBinder instance.
+ */
+ public interface BinderChecker {
+ IInterface asInterface(IBinder binder);
+ boolean checkType(IInterface service);
+ }
+
+ /**
+ * Create a new ManagedApplicationService object but do not yet bind to the user service.
+ *
+ * @param context a Context to use for binding the application service.
+ * @param component the {@link ComponentName} of the application service to bind.
+ * @param userId the user ID of user to bind the application service as.
+ * @param clientLabel the resource ID of a label displayed to the user indicating the
+ * binding service.
+ * @param settingsAction an action that can be used to open the Settings UI to enable/disable
+ * binding to these services.
+ * @param binderChecker an interface used to validate the returned binder object.
+ * @return a ManagedApplicationService instance.
+ */
+ public static ManagedApplicationService build(@NonNull final Context context,
+ @NonNull final ComponentName component, final int userId, @NonNull int clientLabel,
+ @NonNull String settingsAction, @NonNull BinderChecker binderChecker) {
+ return new ManagedApplicationService(context, component, userId, clientLabel,
+ settingsAction, binderChecker);
+ }
+
+ /**
+ * @return the user ID of the user that owns the bound service.
+ */
+ public int getUserId() {
+ return mUserId;
+ }
+
+ /**
+ * @return the component of the bound service.
+ */
+ public ComponentName getComponent() {
+ return mComponent;
+ }
+
+ /**
+ * Asynchronously unbind from the application service if the bound service component and user
+ * does not match the given signature.
+ *
+ * @param componentName the component that must match.
+ * @param userId the user ID that must match.
+ * @return {@code true} if not matching.
+ */
+ public boolean disconnectIfNotMatching(final ComponentName componentName, final int userId) {
+ if (matches(componentName, userId)) {
+ return false;
+ }
+ disconnect();
+ return true;
+ }
+
+ /**
+ * Asynchronously unbind from the application service if bound.
+ */
+ public void disconnect() {
+ synchronized (mLock) {
+ // Wipe out pending connections
+ mPendingConnection = null;
+
+ // Unbind existing connection, if it exists
+ if (mConnection != null) {
+ mContext.unbindService(mConnection);
+ mConnection = null;
+ }
+
+ mBoundInterface = null;
+ }
+ }
+
+ /**
+ * Asynchronously bind to the application service if not bound.
+ */
+ public void connect() {
+ synchronized (mLock) {
+ if (mConnection != null || mPendingConnection != null) {
+ // We're already connected or are trying to connect
+ return;
+ }
+
+ final PendingIntent pendingIntent = PendingIntent.getActivity(
+ mContext, 0, new Intent(mSettingsAction), 0);
+ final Intent intent = new Intent().setComponent(mComponent).
+ putExtra(Intent.EXTRA_CLIENT_LABEL, mClientLabel).
+ putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
+
+ final ServiceConnection serviceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
+ synchronized (mLock) {
+ if (mPendingConnection == this) {
+ // No longer pending, remove from pending connection
+ mPendingConnection = null;
+ mConnection = this;
+ } else {
+ // Service connection wasn't pending, must have been disconnected
+ mContext.unbindService(this);
+ }
+
+ try {
+ iBinder.linkToDeath(mDeathRecipient, 0);
+ mBoundInterface = mChecker.asInterface(iBinder);
+ if (!mChecker.checkType(mBoundInterface)) {
+ // Received an invalid binder, disconnect
+ mContext.unbindService(this);
+ mBoundInterface = null;
+ }
+ } catch (RemoteException e) {
+ // DOA
+ Slog.w(TAG, "Unable to bind service: " + intent, e);
+ mBoundInterface = null;
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName componentName) {
+ Slog.w(TAG, "Service disconnected: " + intent);
+ }
+ };
+
+ mPendingConnection = serviceConnection;
+
+ try {
+ if (!mContext.bindServiceAsUser(intent, serviceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+ new UserHandle(mUserId))) {
+ Slog.w(TAG, "Unable to bind service: " + intent);
+ }
+ } catch (SecurityException e) {
+ Slog.w(TAG, "Unable to bind service: " + intent, e);
+ }
+ }
+ }
+
+ private boolean matches(final ComponentName component, final int userId) {
+ return Objects.equals(mComponent, component) && mUserId == userId;
+ }
+}
diff --git a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
new file mode 100644
index 0000000..1363fb9
--- /dev/null
+++ b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
@@ -0,0 +1,282 @@
+/**
+ * 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.vr;
+
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.content.PackageMonitor;
+import com.android.server.vr.SettingsObserver.SettingChangeListener;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Detects changes in packages, settings, and current users that may affect whether components
+ * implementing a given service can be run.
+ *
+ * @hide
+ */
+public class EnabledComponentsObserver implements SettingChangeListener {
+
+ private static final String TAG = EnabledComponentsObserver.class.getSimpleName();
+ private static final String ENABLED_SERVICES_SEPARATOR = ":";
+
+ public static final int NO_ERROR = 0;
+ public static final int DISABLED = -1;
+ public static final int NOT_INSTALLED = -2;
+
+ private final Object mLock;
+ private final Context mContext;
+ private final String mSettingName;
+ private final String mServiceName;
+ private final String mServicePermission;
+ private final SparseArray<ArraySet<ComponentName>> mInstalledSet = new SparseArray<>();
+ private final SparseArray<ArraySet<ComponentName>> mEnabledSet = new SparseArray<>();
+ private final Set<EnabledComponentChangeListener> mEnabledComponentListeners = new ArraySet<>();
+
+ /**
+ * Implement this to receive callbacks when relevant changes to the allowed components occur.
+ */
+ public interface EnabledComponentChangeListener {
+
+ /**
+ * Called when a change in the allowed components occurs.
+ */
+ void onEnabledComponentChanged();
+ }
+
+ private EnabledComponentsObserver(@NonNull Context context, @NonNull String settingName,
+ @NonNull String servicePermission, @NonNull String serviceName, @NonNull Object lock,
+ @NonNull Collection<EnabledComponentChangeListener> listeners) {
+ mLock = lock;
+ mContext = context;
+ mSettingName = settingName;
+ mServiceName = serviceName;
+ mServicePermission = servicePermission;
+ mEnabledComponentListeners.addAll(listeners);
+ }
+
+ /**
+ * Create a EnabledComponentObserver instance.
+ *
+ * @param context the context to query for changes.
+ * @param handler a handler to receive lifecycle events from system services on.
+ * @param settingName the name of a setting to monitor for a list of enabled components.
+ * @param looper a {@link Looper} to use for receiving package callbacks.
+ * @param servicePermission the permission required by the components to be bound.
+ * @param serviceName the intent action implemented by the tracked components.
+ * @param lock a lock object used to guard instance state in all callbacks and method calls.
+ * @return an EnableComponentObserver instance.
+ */
+ public static EnabledComponentsObserver build(@NonNull Context context,
+ @NonNull Handler handler, @NonNull String settingName, @NonNull Looper looper,
+ @NonNull String servicePermission, @NonNull String serviceName,
+ @NonNull final Object lock,
+ @NonNull Collection<EnabledComponentChangeListener> listeners) {
+
+ SettingsObserver s = SettingsObserver.build(context, handler, settingName);
+
+ final EnabledComponentsObserver o = new EnabledComponentsObserver(context, settingName,
+ servicePermission, serviceName, lock, listeners);
+
+ PackageMonitor packageMonitor = new PackageMonitor() {
+ @Override
+ public void onSomePackagesChanged() {
+ o.onPackagesChanged();
+
+ }
+
+ @Override
+ public void onPackageDisappeared(String packageName, int reason) {
+ o.onPackagesChanged();
+
+ }
+
+ @Override
+ public void onPackageModified(String packageName) {
+ o.onPackagesChanged();
+
+ }
+
+ @Override
+ public boolean onHandleForceStop(Intent intent, String[] packages, int uid,
+ boolean doit) {
+ o.onPackagesChanged();
+
+ return super.onHandleForceStop(intent, packages, uid, doit);
+ }
+ };
+
+ packageMonitor.register(context, looper, UserHandle.ALL, true);
+
+ s.addListener(o);
+
+ return o;
+
+ }
+
+ public void onPackagesChanged() {
+ rebuildAll();
+ }
+
+ @Override
+ public void onSettingChanged() {
+ rebuildAll();
+ }
+
+ @Override
+ public void onSettingRestored(String prevValue, String newValue, int userId) {
+ rebuildAll();
+ }
+
+ public void onUsersChanged() {
+ rebuildAll();
+ }
+
+ /**
+ * Rebuild the sets of allowed components for each current user profile.
+ */
+ public void rebuildAll() {
+ synchronized (mLock) {
+ mInstalledSet.clear();
+ mEnabledSet.clear();
+ final int[] userIds = getCurrentProfileIds();
+ for (int i : userIds) {
+ ArraySet<ComponentName> implementingPackages = loadComponentNamesForUser(i);
+ ArraySet<ComponentName> packagesFromSettings =
+ loadComponentNamesFromSetting(mSettingName, i);
+ packagesFromSettings.retainAll(implementingPackages);
+
+ mInstalledSet.put(i, implementingPackages);
+ mEnabledSet.put(i, packagesFromSettings);
+
+ }
+ }
+ sendSettingChanged();
+ }
+
+ /**
+ * Check whether a given component is present and enabled for the given user.
+ *
+ * @param component the component to check.
+ * @param userId the user ID for the component to check.
+ * @return {@code true} if present and enabled.
+ */
+ public int isValid(ComponentName component, int userId) {
+ synchronized (mLock) {
+ ArraySet<ComponentName> installedComponents = mInstalledSet.get(userId);
+ if (installedComponents == null || !installedComponents.contains(component)) {
+ return NOT_INSTALLED;
+ }
+ ArraySet<ComponentName> validComponents = mEnabledSet.get(userId);
+ if (validComponents == null || !validComponents.contains(component)) {
+ return DISABLED;
+ }
+ return NO_ERROR;
+ }
+ }
+
+ private int[] getCurrentProfileIds() {
+ UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ if (userManager == null) {
+ return null;
+ }
+ int currentUserId = ActivityManager.getCurrentUser();
+ List<UserInfo> profiles = userManager.getProfiles(currentUserId);
+ if (profiles == null) {
+ return null;
+ }
+ final int s = profiles.size();
+ int[] userIds = new int[s];
+ int ctr = 0;
+ for (UserInfo info : profiles) {
+ userIds[ctr++] = info.id;
+ }
+ return userIds;
+ }
+
+ private ArraySet<ComponentName> loadComponentNamesForUser(int userId) {
+ ArraySet<ComponentName> installed = new ArraySet<>();
+ PackageManager pm = mContext.getPackageManager();
+ Intent queryIntent = new Intent(mServiceName);
+ List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
+ queryIntent,
+ PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
+ userId);
+ if (installedServices != null) {
+ for (int i = 0, count = installedServices.size(); i < count; i++) {
+ ResolveInfo resolveInfo = installedServices.get(i);
+ ServiceInfo info = resolveInfo.serviceInfo;
+
+ ComponentName component = new ComponentName(info.packageName, info.name);
+ if (!mServicePermission.equals(info.permission)) {
+ Slog.w(TAG, "Skipping service " + info.packageName + "/" + info.name
+ + ": it does not require the permission "
+ + mServicePermission);
+ continue;
+ }
+ installed.add(component);
+ }
+ }
+ return installed;
+ }
+
+ private ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
+ int userId) {
+ final ContentResolver cr = mContext.getContentResolver();
+ String settingValue = Settings.Secure.getStringForUser(
+ cr,
+ settingName,
+ userId);
+ if (TextUtils.isEmpty(settingValue))
+ return new ArraySet<>();
+ String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR);
+ ArraySet<ComponentName> result = new ArraySet<>(restored.length);
+ for (int i = 0; i < restored.length; i++) {
+ ComponentName value = ComponentName.unflattenFromString(restored[i]);
+ if (null != value) {
+ result.add(value);
+ }
+ }
+ return result;
+ }
+
+ private void sendSettingChanged() {
+ for (EnabledComponentChangeListener l : mEnabledComponentListeners) {
+ l.onEnabledComponentChanged();
+ }
+ }
+
+}
diff --git a/services/core/java/com/android/server/vr/SettingsObserver.java b/services/core/java/com/android/server/vr/SettingsObserver.java
new file mode 100644
index 0000000..ce76863
--- /dev/null
+++ b/services/core/java/com/android/server/vr/SettingsObserver.java
@@ -0,0 +1,145 @@
+/**
+ * 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.vr;
+
+import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.ArraySet;
+
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Detects changes in a given setting.
+ *
+ * @hide
+ */
+public class SettingsObserver {
+
+ private final String mSecureSettingName;
+ private final BroadcastReceiver mSettingRestorReceiver;
+ private final ContentObserver mContentObserver;
+ private final Set<SettingChangeListener> mSettingsListeners = new ArraySet<>();
+
+ /**
+ * Implement this to receive callbacks when the setting tracked by this observer changes.
+ */
+ public interface SettingChangeListener {
+
+ /**
+ * Called when the tracked setting has changed.
+ */
+ void onSettingChanged();
+
+
+ /**
+ * Called when the tracked setting has been restored for a particular user.
+ *
+ * @param prevValue the previous value of the setting.
+ * @param newValue the new value of the setting.
+ * @param userId the user ID for which this setting has been restored.
+ */
+ void onSettingRestored(String prevValue, String newValue, int userId);
+ }
+
+ private SettingsObserver(@NonNull final Context context, @NonNull final Handler handler,
+ @NonNull final Uri settingUri, @NonNull final String secureSettingName) {
+
+ mSecureSettingName = secureSettingName;
+ mSettingRestorReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
+ String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
+ if (Objects.equals(element, secureSettingName)) {
+ String prevValue = intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE);
+ String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
+ sendSettingRestored(prevValue, newValue, getSendingUserId());
+ }
+ }
+ }
+ };
+
+ mContentObserver = new ContentObserver(handler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (uri == null || settingUri.equals(uri)) {
+ sendSettingChanged();
+ }
+ }
+ };
+
+ ContentResolver resolver = context.getContentResolver();
+ resolver.registerContentObserver(settingUri, false, mContentObserver,
+ UserHandle.USER_ALL);
+ }
+
+ /**
+ * Create a SettingsObserver instance.
+ *
+ * @param context the context to query for settings changes.
+ * @param handler the handler to use for a settings ContentObserver.
+ * @param settingName the setting to track.
+ * @return a SettingsObserver instance.
+ */
+ public static SettingsObserver build(@NonNull Context context, @NonNull Handler handler,
+ @NonNull String settingName) {
+ Uri settingUri = Settings.Secure.getUriFor(settingName);
+
+ return new SettingsObserver(context, handler, settingUri, settingName);
+ }
+
+ /**
+ * Add a listener for setting changes.
+ *
+ * @param listener a {@link SettingChangeListener} instance.
+ */
+ public void addListener(@NonNull SettingChangeListener listener) {
+ mSettingsListeners.add(listener);
+
+ }
+
+ /**
+ * Remove a listener for setting changes.
+ *
+ * @param listener a {@link SettingChangeListener} instance.
+ */
+ public void removeListener(@NonNull SettingChangeListener listener) {
+ mSettingsListeners.remove(listener);
+
+ }
+
+ private void sendSettingChanged() {
+ for (SettingChangeListener l : mSettingsListeners) {
+ l.onSettingChanged();
+ }
+ }
+
+ private void sendSettingRestored(final String prevValue, final String newValue, final int userId) {
+ for (SettingChangeListener l : mSettingsListeners) {
+ l.onSettingRestored(prevValue, newValue, userId);
+ }
+ }
+
+}
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 42db364..6b5523f 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,14 +15,22 @@
*/
package com.android.server.vr;
+import android.annotation.NonNull;
+import android.content.ComponentName;
+
/**
- * VR mode local system service interface.
+ * Service for accessing the VR mode manager.
*
* @hide Only for use within system server.
*/
public abstract class VrManagerInternal {
/**
+ * The error code returned on success.
+ */
+ public static final int NO_ERROR = 0;
+
+ /**
* Return current VR mode state.
*
* @return {@code true} if VR mode is enabled.
@@ -33,8 +41,11 @@
* Set the current VR mode state.
*
* @param enabled {@code true} to enable VR mode.
+ * @param packageName The package name of the requested VrListenerService to bind.
+ * @param userId the user requesting the VrListenerService component.
*/
- public abstract void setVrMode(boolean enabled);
+ public abstract void setVrMode(boolean enabled, @NonNull ComponentName packageName,
+ int userId);
/**
* Add a listener for VR mode state changes.
@@ -43,13 +54,23 @@
* </p>
* @param listener the listener instance to add.
*/
- public abstract void registerListener(VrStateListener listener);
+ public abstract void registerListener(@NonNull VrStateListener listener);
/**
* Remove the listener from the current set of listeners.
*
* @param listener the listener to remove.
*/
- public abstract void unregisterListener(VrStateListener listener);
+ public abstract void unregisterListener(@NonNull VrStateListener listener);
+
+ /**
+ * Return NO_ERROR if the given package is installed on the device and enabled as a
+ * VrListenerService for the given current user, or a negative error code indicating a failure.
+ *
+ * @param packageName the name of the package to check, or null to select the default package.
+ * @return NO_ERROR if the given package is installed and is enabled, or a negative error code
+ * given in {@link android.service.vr.VrModeException} on failure.
+ */
+ public abstract int hasVrPackage(@NonNull ComponentName packageName, int userId);
}
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 7611527..f5914faf 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,26 +16,53 @@
package com.android.server.vr;
import android.app.AppOpsManager;
+import android.annotation.NonNull;
import android.content.Context;
+import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Binder;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Looper;
import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.vr.IVrListener;
+import android.service.vr.VrListenerService;
import android.util.ArraySet;
import android.util.Slog;
+import com.android.internal.R;
import com.android.server.SystemService;
+import com.android.server.vr.EnabledComponentsObserver.EnabledComponentChangeListener;
+import com.android.server.utils.ManagedApplicationService;
+import com.android.server.utils.ManagedApplicationService.BinderChecker;
import java.util.ArrayList;
+import java.util.Set;
/**
- * Service tracking whether VR mode is active, and notifying listening system services of state
- * changes.
+ * Service tracking whether VR mode is active, and notifying listening services of state changes.
+ * <p/>
+ * Services running in system server may modify the state of VrManagerService via the interface in
+ * VrManagerInternal, and may register to receive callbacks when the system VR mode changes via the
+ * interface given in VrStateListener.
+ * <p/>
+ * Device vendors may choose to receive VR state changes by implementing the VR mode HAL, e.g.:
+ * hardware/libhardware/modules/vr
+ * <p/>
+ * In general applications may enable or disable VR mode by calling
+ * {@link android.app.Activity#setVrMode)}. An application may also implement a service to be run
+ * while in VR mode by implementing {@link android.service.vr.VrListenerService}.
*
- * {@hide}
+ * @see {@link android.service.vr.VrListenerService}
+ * @see {@link com.android.server.vr.VrManagerInternal}
+ * @see {@link com.android.server.vr.VrStateListener}
+ *
+ * @hide
*/
-public class VrManagerService extends SystemService {
+public class VrManagerService extends SystemService implements EnabledComponentChangeListener{
public static final String TAG = "VrManagerService";
@@ -46,9 +73,45 @@
private final IBinder mOverlayToken = new Binder();
+ // State protected by mLock
private boolean mVrModeEnabled = false;
- private ArraySet<VrStateListener> mListeners = new ArraySet<>();
+ private final Set<VrStateListener> mListeners = new ArraySet<>();
+ private EnabledComponentsObserver mComponentObserver;
+ private ManagedApplicationService mCurrentVrService;
+ private Context mContext;
+ private static final BinderChecker sBinderChecker = new BinderChecker() {
+ @Override
+ public IInterface asInterface(IBinder binder) {
+ return IVrListener.Stub.asInterface(binder);
+ }
+
+ @Override
+ public boolean checkType(IInterface service) {
+ return service instanceof IVrListener;
+ }
+ };
+
+ /**
+ * Called when a user, package, or setting changes that could affect whether or not the
+ * currently bound VrListenerService is changed.
+ */
+ @Override
+ public void onEnabledComponentChanged() {
+ synchronized (mLock) {
+ if (mCurrentVrService == null) {
+ return; // No active services
+ }
+
+ // There is an active service, update it if needed
+ updateCurrentVrServiceLocked(mVrModeEnabled, mCurrentVrService.getComponent(),
+ mCurrentVrService.getUserId());
+ }
+ }
+
+ /**
+ * Implementation of VrManagerInternal. Callable only from system services.
+ */
private final class LocalService extends VrManagerInternal {
@Override
public boolean isInVrMode() {
@@ -56,8 +119,8 @@
}
@Override
- public void setVrMode(boolean enabled) {
- VrManagerService.this.setVrMode(enabled);
+ public void setVrMode(boolean enabled, ComponentName packageName, int userId) {
+ VrManagerService.this.setVrMode(enabled, packageName, userId);
}
@Override
@@ -69,6 +132,11 @@
public void unregisterListener(VrStateListener listener) {
VrManagerService.this.removeListener(listener);
}
+
+ @Override
+ public int hasVrPackage(ComponentName packageName, int userId) {
+ return VrManagerService.this.hasVrPackage(packageName, userId);
+ }
}
public VrManagerService(Context context) {
@@ -79,36 +147,60 @@
public void onStart() {
synchronized(mLock) {
initializeNative();
+ mContext = getContext();
}
publishLocalService(VrManagerInternal.class, new LocalService());
}
- private void addListener(VrStateListener listener) {
- synchronized (mLock) {
- mListeners.add(listener);
- }
- }
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+ synchronized (mLock) {
+ Looper looper = Looper.getMainLooper();
+ Handler handler = new Handler(looper);
+ ArrayList<EnabledComponentChangeListener> listeners = new ArrayList<>();
+ listeners.add(this);
+ mComponentObserver = EnabledComponentsObserver.build(mContext, handler,
+ Settings.Secure.ENABLED_VR_LISTENERS, looper,
+ android.Manifest.permission.BIND_VR_LISTENER_SERVICE,
+ VrListenerService.SERVICE_INTERFACE, mLock, listeners);
- private void removeListener(VrStateListener listener) {
- synchronized (mLock) {
- mListeners.remove(listener);
- }
- }
-
- private void setVrMode(boolean enabled) {
- synchronized (mLock) {
- if (mVrModeEnabled != enabled) {
- mVrModeEnabled = enabled;
- // Log mode change event.
- Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled"));
- setVrModeNative(mVrModeEnabled);
- updateOverlayStateLocked();
- onVrModeChangedLocked();
+ mComponentObserver.rebuildAll();
}
}
}
+ @Override
+ public void onStartUser(int userHandle) {
+ synchronized (mLock) {
+ mComponentObserver.onUsersChanged();
+ }
+ }
+
+ @Override
+ public void onSwitchUser(int userHandle) {
+ synchronized (mLock) {
+ mComponentObserver.onUsersChanged();
+ }
+
+ }
+
+ @Override
+ public void onStopUser(int userHandle) {
+ synchronized (mLock) {
+ mComponentObserver.onUsersChanged();
+ }
+
+ }
+
+ @Override
+ public void onCleanupUser(int userHandle) {
+ synchronized (mLock) {
+ mComponentObserver.onUsersChanged();
+ }
+ }
+
private void updateOverlayStateLocked() {
final long identity = Binder.clearCallingIdentity();
try {
@@ -122,18 +214,134 @@
}
}
+ /**
+ * Send VR mode changes (if the mode state has changed), and update the bound/unbound state of
+ * the currently selected VR listener service. If the component selected for the VR listener
+ * service has changed, unbind the previous listener and bind the new listener (if enabled).
+ * <p/>
+ * Note: Must be called while holding {@code mLock}.
+ *
+ * @param enabled new state for VR mode.
+ * @param component new component to be bound as a VR listener.
+ * @param userId user owning the component to be bound.
+ *
+ * @return {@code true} if the component/user combination specified is valid.
+ */
+ private boolean updateCurrentVrServiceLocked(boolean enabled,
+ @NonNull ComponentName component, int userId) {
+
+ // Always send mode change events.
+ changeVrModeLocked(enabled);
+
+ boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
+ EnabledComponentsObserver.NO_ERROR);
+
+ if (!enabled || !validUserComponent) {
+ // Unbind whatever is running
+ if (mCurrentVrService != null) {
+ Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
+ mCurrentVrService.getUserId());
+ mCurrentVrService.disconnect();
+ mCurrentVrService = null;
+ }
+ return validUserComponent;
+ }
+
+ if (mCurrentVrService != null) {
+ // Unbind any running service that doesn't match the component/user selection
+ if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
+ Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
+ mCurrentVrService.getUserId());
+ mCurrentVrService = VrManagerService.create(mContext, component, userId);
+ mCurrentVrService.connect();
+ Slog.i(TAG, "Connecting " + mCurrentVrService.getComponent() + " for user " +
+ mCurrentVrService.getUserId());
+ }
+ // The service with the correct component/user is bound
+ } else {
+ // Nothing was previously running, bind a new service
+ mCurrentVrService = VrManagerService.create(mContext, component, userId);
+ mCurrentVrService.connect();
+ Slog.i(TAG, "Connecting " + mCurrentVrService.getComponent() + " for user " +
+ mCurrentVrService.getUserId());
+ }
+
+ return validUserComponent;
+ }
+
+ /**
+ * Send VR mode change callbacks to HAL and system services if mode has actually changed.
+ * <p/>
+ * Note: Must be called while holding {@code mLock}.
+ *
+ * @param enabled new state of the VR mode.
+ */
+ private void changeVrModeLocked(boolean enabled) {
+ if (mVrModeEnabled != enabled) {
+ mVrModeEnabled = enabled;
+
+ // Log mode change event.
+ Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled"));
+ setVrModeNative(mVrModeEnabled);
+
+ updateOverlayStateLocked();
+ onVrModeChangedLocked();
+ }
+ }
+
+ /**
+ * Notify system services of VR mode change.
+ * <p/>
+ * Note: Must be called while holding {@code mLock}.
+ */
+ private void onVrModeChangedLocked() {
+ for (VrStateListener l : mListeners) {
+ l.onVrStateChanged(mVrModeEnabled);
+ }
+ }
+
+ /**
+ * Helper function for making ManagedApplicationService instances.
+ */
+ private static ManagedApplicationService create(@NonNull Context context,
+ @NonNull ComponentName component, int userId) {
+ return ManagedApplicationService.build(context, component, userId,
+ R.string.vr_listener_binding_label, Settings.ACTION_VR_LISTENER_SETTINGS,
+ sBinderChecker);
+ }
+
+ /*
+ * Implementation of VrManagerInternal calls. These are callable from system services.
+ */
+
+ private boolean setVrMode(boolean enabled, @NonNull ComponentName targetPackageName,
+ int userId) {
+ synchronized (mLock) {
+ return updateCurrentVrServiceLocked(enabled, targetPackageName, userId);
+ }
+ }
+
private boolean getVrMode() {
synchronized (mLock) {
return mVrModeEnabled;
}
}
- /**
- * Notify system services of VR mode change.
- */
- private void onVrModeChangedLocked() {
- for (VrStateListener l : mListeners) {
- l.onVrStateChanged(mVrModeEnabled);
+ private void addListener(VrStateListener listener) {
+ synchronized (mLock) {
+ mListeners.add(listener);
+ }
+ }
+
+ private void removeListener(VrStateListener listener) {
+ synchronized (mLock) {
+ mListeners.remove(listener);
+ }
+ }
+
+ private int hasVrPackage(@NonNull ComponentName targetPackageName, int userId) {
+ synchronized (mLock) {
+ return mComponentObserver.isValid(targetPackageName, userId);
}
}
}
diff --git a/services/core/java/com/android/server/vr/VrStateListener.java b/services/core/java/com/android/server/vr/VrStateListener.java
index b8af4b2..b0603c80 100644
--- a/services/core/java/com/android/server/vr/VrStateListener.java
+++ b/services/core/java/com/android/server/vr/VrStateListener.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,9 @@
package com.android.server.vr;
/**
- * Listener for state changes in VrManagerService,
+ * Listener for state changes in VrManagerService.
+ *
+ * @hide Only for use within system server.
*/
public abstract class VrStateListener {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index ba0d340..ccbdad2 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;
}
}
@@ -1309,7 +1317,7 @@
List<ResolveInfo> ris =
mIPackageManager.queryIntentServices(intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- PackageManager.GET_META_DATA, serviceUserId);
+ PackageManager.GET_META_DATA, serviceUserId).getList();
for (int i=0; i<ris.size(); i++) {
ServiceInfo rsi = ris.get(i).serviceInfo;
if (rsi.name.equals(si.name) &&
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index a81fba0..55b3c7b 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -190,7 +190,8 @@
public void clearThumbnail() {
if (thumbnail != null) {
- thumbnail.destroy();
+ thumbnail.hide();
+ mService.mWindowPlacerLocked.destroyAfterTransaction(thumbnail);
thumbnail = null;
}
deferThumbnailDestruction = false;
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/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index fc5d8ce..95be233 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -84,10 +84,13 @@
/** The user of this dim layer. */
private final DimLayerUser mUser;
- DimLayer(WindowManagerService service, DimLayerUser user, int displayId) {
+ private final String mName;
+
+ DimLayer(WindowManagerService service, DimLayerUser user, int displayId, String name) {
mUser = user;
mDisplayId = displayId;
mService = service;
+ mName = name;
if (DEBUG_DIM_LAYER) Slog.v(TAG, "Ctor: displayId=" + displayId);
}
@@ -100,7 +103,7 @@
16, 16, PixelFormat.OPAQUE,
SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN);
} else {
- mDimSurface = new SurfaceControl(service.mFxSession, TAG,
+ mDimSurface = new SurfaceControl(service.mFxSession, mName,
16, 16, PixelFormat.OPAQUE,
SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN);
}
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index 6d1cec4..97d0ae0 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -10,6 +10,8 @@
import android.util.Slog;
import android.util.TypedValue;
+import com.android.server.wm.DimLayer.DimLayerUser;
+
import java.io.PrintWriter;
/**
@@ -18,7 +20,8 @@
* as well as other use cases (such as dimming above a dead window).
*/
class DimLayerController {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "DimLayerController" : TAG_WM;
+ private static final String TAG_LOCAL = "DimLayerController";
+ private static final String TAG = TAG_WITH_CLASS_NAME ? TAG_LOCAL : TAG_WM;
/** Amount of time in milliseconds to animate the dim surface from one value to another,
* when no window animation is driving it. */
@@ -63,7 +66,8 @@
newDimLayer = state.dimLayer;
} else {
// Create new full screen dim layer.
- newDimLayer = new DimLayer(mDisplayContent.mService, dimLayerUser, displayId);
+ newDimLayer = new DimLayer(mDisplayContent.mService, dimLayerUser, displayId,
+ getDimLayerTag(dimLayerUser));
}
dimLayerUser.getDimBounds(mTmpBounds);
newDimLayer.setBounds(mTmpBounds);
@@ -73,7 +77,8 @@
}
} else {
newDimLayer = (state.dimLayer == null || previousFullscreen)
- ? new DimLayer(mDisplayContent.mService, dimLayerUser, displayId)
+ ? new DimLayer(mDisplayContent.mService, dimLayerUser, displayId,
+ getDimLayerTag(dimLayerUser))
: state.dimLayer;
dimLayerUser.getDimBounds(mTmpBounds);
newDimLayer.setBounds(mTmpBounds);
@@ -81,6 +86,10 @@
state.dimLayer = newDimLayer;
}
+ private static String getDimLayerTag(DimLayerUser dimLayerUser) {
+ return TAG_LOCAL + "/" + dimLayerUser.toShortString();
+ }
+
private DimLayerState getOrCreateDimLayerState(DimLayer.DimLayerUser dimLayerUser) {
if (DEBUG_DIM_LAYER) Slog.v(TAG, "getOrCreateDimLayerState, dimLayerUser="
+ dimLayerUser.toShortString());
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index b6aa3f2..9bceee7 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -16,6 +16,17 @@
package com.android.server.wm;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.DOCKED_TOP;
+import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
+import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
import android.content.Context;
import android.graphics.Rect;
import android.os.RemoteCallbackList;
@@ -30,19 +41,6 @@
import com.android.server.wm.DimLayer.DimLayerUser;
-import java.util.ArrayList;
-
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.view.WindowManager.DOCKED_BOTTOM;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_RIGHT;
-import static android.view.WindowManager.DOCKED_TOP;
-import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
-import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
/**
* Keeps information about the docked stack divider.
*/
@@ -106,7 +104,8 @@
com.android.internal.R.dimen.docked_stack_divider_thickness);
mDividerInsets = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_insets);
- mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId());
+ mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId(),
+ "DockedStackDim");
mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
context, android.R.interpolator.fast_out_slow_in);
}
@@ -247,8 +246,9 @@
void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
SurfaceControl.openTransaction();
- TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
- boolean visibleAndValid = visible && stack != null;
+ final TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
+ final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
+ boolean visibleAndValid = visible && stack != null && dockedStack != null;
if (visibleAndValid) {
stack.getDimBounds(mTmpRect);
if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
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/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index f7035c5..92701de 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -60,7 +60,8 @@
import java.lang.annotation.RetentionPolicy;
class TaskPositioner implements DimLayer.DimLayerUser {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskPositioner" : TAG_WM;
+ private static final String TAG_LOCAL = "TaskPositioner";
+ private static final String TAG = TAG_WITH_CLASS_NAME ? TAG_LOCAL : TAG_WM;
// The margin the pointer position has to be within the side of the screen to be
// considered at the side of the screen.
@@ -287,7 +288,7 @@
}
mService.pauseRotationLocked();
- mDimLayer = new DimLayer(mService, this, mDisplay.getDisplayId());
+ mDimLayer = new DimLayer(mService, this, mDisplay.getDisplayId(), TAG_LOCAL);
mSideMargin = dipToPixel(SIDE_MARGIN_DIP, mDisplayMetrics);
mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics);
mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics);
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 07a6514..676b90f 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;
@@ -574,7 +585,8 @@
}
mDisplayContent = displayContent;
- mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId());
+ mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId(),
+ "animation background stackId=" + mStackId);
Rect bounds = null;
final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
@@ -1128,17 +1140,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 +1196,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/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 85bddee..4698e4e 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -771,6 +771,7 @@
}
mService.destroyPreservedSurfaceLocked();
+ mService.mWindowPlacerLocked.destroyPendingSurfaces();
if (DEBUG_WINDOW_TRACE) {
Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
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..617d2b4 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -101,6 +101,10 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
class WindowList extends ArrayList<WindowState> {
+ WindowList() {}
+ WindowList(WindowList windowList) {
+ super(windowList);
+ }
}
/**
@@ -184,6 +188,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 +442,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 +643,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 +669,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 +728,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 +780,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 +1363,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 +1629,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 +1916,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 +2075,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 +2109,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 +2507,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 +2565,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..bf8a62e 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;
@@ -433,9 +434,12 @@
+ " remove=" + mWin.mRemoveOnExit
+ " windowAnimating=" + isWindowAnimating());
- final int N = mWin.mChildWindows.size();
- for (int i=0; i<N; i++) {
- mWin.mChildWindows.get(i).mWinAnimator.finishExit();
+ if (!mWin.mChildWindows.isEmpty()) {
+ // Copying to a different list as multiple children can be removed.
+ final WindowList childWindows = new WindowList(mWin.mChildWindows);
+ for (int i = childWindows.size() - 1; i >= 0; i--) {
+ childWindows.get(i).mWinAnimator.finishExit();
+ }
}
if (mEnteringAnimation) {
@@ -467,9 +471,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 +1118,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 +1190,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 +1199,10 @@
clipRect.setEmpty();
}
+ return clipRect;
+ }
+
+ void updateSurfaceWindowCrop(Rect clipRect, boolean recoveringMemory) {
if (!clipRect.equals(mLastClipRect)) {
mLastClipRect.set(clipRect);
mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
@@ -1237,6 +1244,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 +1259,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 +1308,6 @@
w.applyDimLayerIfNeeded();
}
- updateSurfaceWindowCrop(recoveringMemory);
}
void prepareSurfaceLocked(final boolean recoveringMemory) {
@@ -1409,7 +1446,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..18aa186 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -46,7 +46,6 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Debug;
-import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -125,6 +124,8 @@
}
private final LayerAndToken mTmpLayerAndToken = new LayerAndToken();
+ private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>();
+
public WindowSurfacePlacer(WindowManagerService service) {
mService = service;
mWallpaperControllerLocked = mService.mWallpaperControllerLocked;
@@ -542,6 +543,7 @@
mService.enableScreenIfNeededLocked();
mService.scheduleAnimationLocked();
+ mService.mWindowPlacerLocked.destroyPendingSurfaces();
if (DEBUG_WINDOW_TRACE) Slog.e(TAG,
"performSurfacePlacementInner exit: animating=" + mService.mAnimator.isAnimating());
@@ -651,6 +653,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 +686,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);
}
@@ -1618,6 +1622,25 @@
}
}
+ /**
+ * Puts the {@param surface} into a pending list to be destroyed after the current transaction
+ * has been committed.
+ */
+ void destroyAfterTransaction(SurfaceControl surface) {
+ mPendingDestroyingSurfaces.add(surface);
+ }
+
+ /**
+ * Destroys any surfaces that have been put into the pending list with
+ * {@link #destroyAfterTransaction}.
+ */
+ void destroyPendingSurfaces() {
+ for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
+ mPendingDestroyingSurfaces.get(i).destroy();
+ }
+ mPendingDestroyingSurfaces.clear();
+ }
+
public void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mTraversalScheduled="); pw.println(mTraversalScheduled);
}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index c97323c..60ed497 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,9 @@
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(MultipathIndicator,
+ static_cast<int32_t>(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 +1218,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 +1245,9 @@
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(MultipathIndicator,
+ static_cast<int32_t>(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 +1427,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 +1455,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..d979675 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)) {
@@ -2624,7 +2638,7 @@
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
- } catch (RuntimeException e) {
+ } catch (RuntimeException | AssertionError e) {
Log.e(LOG_TAG, "Could not connect to KeyChain service", e);
}
if (!hasCert) {
@@ -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);
}
}
@@ -7125,7 +7130,7 @@
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
- parentUserId);
+ parentUserId).getList();
if (VERBOSE_LOG) {
Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable);
@@ -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 0ece6aa..a2d5259 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);
@@ -617,7 +635,6 @@
WallpaperManagerService wallpaper = null;
LocationManagerService location = null;
CountryDetectorService countryDetector = null;
- TextServicesManagerService tsms = null;
ILockSettings lockSettings = null;
AssetAtlasService atlas = null;
MediaRouterService mediaRouter = null;
@@ -744,14 +761,7 @@
}
if (!disableNonCoreServices) {
- traceBeginAndSlog("StartTextServicesManagerService");
- try {
- tsms = new TextServicesManagerService(context);
- ServiceManager.addService(Context.TEXT_SERVICES_MANAGER_SERVICE, tsms);
- } catch (Throwable e) {
- reportWtf("starting Text Service Manager Service", e);
- }
- Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class);
}
if (!disableNetwork) {
@@ -1036,6 +1046,7 @@
traceBeginAndSlog("StartNetworkTimeUpdateService");
try {
networkTimeUpdater = new NetworkTimeUpdateService(context);
+ ServiceManager.addService("network_time_update_service", networkTimeUpdater);
} catch (Throwable e) {
reportWtf("starting NetworkTimeUpdate service", e);
}
@@ -1123,19 +1134,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);
@@ -1250,7 +1248,6 @@
final CountryDetectorService countryDetectorF = countryDetector;
final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService;
- final TextServicesManagerService textServiceManagerServiceF = tsms;
final StatusBarManagerService statusBarF = statusBar;
final AssetAtlasService atlasF = atlas;
final InputManagerService inputManagerF = inputManager;
@@ -1366,12 +1363,6 @@
reportWtf("Notifying CommonTimeManagementService running", e);
}
try {
- if (textServiceManagerServiceF != null)
- textServiceManagerServiceF.systemRunning();
- } catch (Throwable e) {
- reportWtf("Notifying TextServicesManagerService running", e);
- }
- try {
if (atlasF != null) atlasF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying AssetAtlasService running", e);
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 46ecc50..c7c5015 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -63,12 +63,9 @@
* @hide
*/
public class IpManager extends StateMachine {
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean VDBG = false;
- private static final boolean NO_CALLBACKS = false;
- private static final boolean SEND_CALLBACKS = true;
-
// For message logging.
private static final Class[] sMessageClasses = { IpManager.class, DhcpClient.class };
private static final SparseArray<String> sWhatToString =
@@ -98,6 +95,10 @@
public void onProvisioningSuccess(LinkProperties newLp) {}
public void onProvisioningFailure(LinkProperties newLp) {}
+ // This is called whenever 464xlat is being enabled or disabled (i.e.
+ // started or stopped).
+ public void on464XlatChange(boolean enabled) {}
+
// Invoked on LinkProperties changes.
public void onLinkPropertiesChange(LinkProperties newLp) {}
@@ -207,6 +208,13 @@
private static final int MAX_LOG_RECORDS = 1000;
+ private static final boolean NO_CALLBACKS = false;
+ private static final boolean SEND_CALLBACKS = true;
+
+ // This must match the interface prefix in clatd.c.
+ // TODO: Revert this hack once IpManager and Nat464Xlat work in concert.
+ private static final String CLAT_PREFIX = "v4-";
+
private final Object mLock = new Object();
private final State mStoppedState = new StoppedState();
private final State mStoppingState = new StoppingState();
@@ -215,6 +223,7 @@
private final String mTag;
private final Context mContext;
private final String mInterfaceName;
+ private final String mClatInterfaceName;
@VisibleForTesting
protected final Callback mCallback;
private final INetworkManagementService mNwService;
@@ -255,6 +264,7 @@
mContext = context;
mInterfaceName = ifName;
+ mClatInterfaceName = CLAT_PREFIX + ifName;
mCallback = callback;
mNwService = nwService;
@@ -265,7 +275,22 @@
public void update() {
sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED);
}
- });
+ }) {
+ @Override
+ public void interfaceAdded(String iface) {
+ if (mClatInterfaceName.equals(iface)) {
+ mCallback.on464XlatChange(true);
+ }
+ }
+
+ @Override
+ public void interfaceRemoved(String iface) {
+ if (mClatInterfaceName.equals(iface)) {
+ mCallback.on464XlatChange(false);
+ }
+ }
+ };
+
try {
mNwService.registerObserver(mNetlinkTracker);
} catch (RemoteException e) {
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/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index e6f4177..8cfc4a3 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -41,13 +41,16 @@
import android.print.IPrintDocumentAdapter;
import android.print.IPrintJobStateChangeListener;
import android.print.IPrintManager;
+import android.print.IPrintServicesChangeListener;
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintAttributes;
import android.print.PrintJobId;
import android.print.PrintJobInfo;
+import android.print.PrintManager;
import android.print.PrinterId;
import android.printservice.PrintServiceInfo;
import android.provider.Settings;
+import android.util.Log;
import android.util.SparseArray;
import com.android.internal.content.PackageMonitor;
@@ -66,6 +69,8 @@
* PrintManager implementation is contained within.
*/
public final class PrintManagerService extends SystemService {
+ private static final String LOG_TAG = "PrintManagerService";
+
private final PrintManagerImpl mPrintManagerImpl;
public PrintManagerService(Context context) {
@@ -253,7 +258,10 @@
}
@Override
- public List<PrintServiceInfo> getEnabledPrintServices(int userId) {
+ public List<PrintServiceInfo> getPrintServices(int selectionFlags, int userId) {
+ Preconditions.checkFlagsArgument(selectionFlags,
+ PrintManager.DISABLED_SERVICES | PrintManager.ENABLED_SERVICES);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -262,34 +270,44 @@
return null;
}
userState = getOrCreateUserStateLocked(resolvedUserId);
-
- // The user state might be updated via the same observer-set as the caller of this
- // interface. If the caller is called back first the user state is not yet updated
- // and the user gets and inconsistent view. Hence force an update.
- userState.updateIfNeededLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
- return userState.getEnabledPrintServices();
+ return userState.getPrintServices(selectionFlags);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
- public List<PrintServiceInfo> getInstalledPrintServices(int userId) {
+ public void setPrintServiceEnabled(ComponentName service, boolean isEnabled, int userId) {
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final int appId = UserHandle.getAppId(Binder.getCallingUid());
+
+ try {
+ if (appId != Process.SYSTEM_UID && appId != UserHandle.getAppId(
+ mContext.getPackageManager().getPackageUidAsUser(
+ PrintManager.PRINT_SPOOLER_PACKAGE_NAME, resolvedUserId))) {
+ throw new SecurityException("Only system and print spooler can call this");
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOG_TAG, "Could not verify caller", e);
+ return;
+ }
+
+ service = Preconditions.checkNotNull(service);
+
final UserState userState;
synchronized (mLock) {
- // Only the current group members can get installed services.
+ // Only the current group members can enable / disable services.
if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
- return null;
+ return;
}
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
try {
- return userState.getInstalledPrintServices();
+ userState.setPrintServiceEnabled(service, isEnabled);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -496,6 +514,50 @@
}
@Override
+ public void addPrintServicesChangeListener(IPrintServicesChangeListener listener,
+ int userId) throws RemoteException {
+ listener = Preconditions.checkNotNull(listener);
+
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final UserState userState;
+ synchronized (mLock) {
+ // Only the current group members can add a print services listener.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+ return;
+ }
+ userState = getOrCreateUserStateLocked(resolvedUserId);
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ userState.addPrintServicesChangeListener(listener);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void removePrintServicesChangeListener(IPrintServicesChangeListener listener,
+ int userId) {
+ listener = Preconditions.checkNotNull(listener);
+
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final UserState userState;
+ synchronized (mLock) {
+ // Only the current group members can remove a print job listener.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+ return;
+ }
+ userState = getOrCreateUserStateLocked(resolvedUserId);
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ userState.removePrintServicesChangeListener(listener);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
fd = Preconditions.checkNotNull(fd);
pw = Preconditions.checkNotNull(pw);
@@ -550,43 +612,79 @@
private void registerBroadcastReceivers() {
PackageMonitor monitor = new PackageMonitor() {
- private void updateServices(String packageName) {
- if (!mUserManager.isUserUnlocked(getChangingUserId())) return;
- synchronized (mLock) {
- // A background user/profile's print jobs are running but there is
- // no UI shown. Hence, if the packages of such a user change we need
- // to handle it as the change may affect ongoing print jobs.
- boolean servicesChanged = false;
- UserState userState = getOrCreateUserStateLocked(getChangingUserId());
+ /**
+ * Checks if the package contains a print service.
+ *
+ * @param packageName The name of the package
+ *
+ * @return true iff the package contains a print service
+ */
+ private boolean hasPrintService(String packageName) {
+ Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
+ intent.setPackage(packageName);
- List<PrintServiceInfo> installedServices = userState
- .getInstalledPrintServices();
- final int numInstalledServices = installedServices.size();
- for (int i = 0; i < numInstalledServices; i++) {
- if (installedServices.get(i).getResolveInfo().serviceInfo.packageName
- .equals(packageName)) {
- servicesChanged = true;
- break;
- }
- }
- if (servicesChanged) {
- userState.updateIfNeededLocked();
+ List<ResolveInfo> installedServices = mContext.getPackageManager()
+ .queryIntentServicesAsUser(intent,
+ GET_SERVICES | MATCH_DEBUG_TRIAGED_MISSING,
+ getChangingUserId());
+
+ return installedServices != null && !installedServices.isEmpty();
+ }
+
+ /**
+ * Checks if there is a print service currently registered for this package.
+ *
+ * @param userState The userstate for the current user
+ * @param packageName The name of the package
+ *
+ * @return true iff the package contained (and might still contain) a print service
+ */
+ private boolean hadPrintService(@NonNull UserState userState, String packageName) {
+ List<PrintServiceInfo> installedServices = userState
+ .getPrintServices(PrintManager.ALL_SERVICES);
+
+ if (installedServices == null) {
+ return false;
+ }
+
+ final int numInstalledServices = installedServices.size();
+ for (int i = 0; i < numInstalledServices; i++) {
+ if (installedServices.get(i).getResolveInfo().serviceInfo.packageName
+ .equals(packageName)) {
+ return true;
}
}
+
+ return false;
}
@Override
public void onPackageModified(String packageName) {
if (!mUserManager.isUserUnlocked(getChangingUserId())) return;
- updateServices(packageName);
- getOrCreateUserStateLocked(getChangingUserId()).prunePrintServices();
+ UserState userState = getOrCreateUserStateLocked(getChangingUserId());
+
+ synchronized (mLock) {
+ if (hadPrintService(userState, packageName)
+ || hasPrintService(packageName)) {
+ userState.updateIfNeededLocked();
+ }
+ }
+
+ userState.prunePrintServices();
}
@Override
public void onPackageRemoved(String packageName, int uid) {
if (!mUserManager.isUserUnlocked(getChangingUserId())) return;
- updateServices(packageName);
- getOrCreateUserStateLocked(getChangingUserId()).prunePrintServices();
+ UserState userState = getOrCreateUserStateLocked(getChangingUserId());
+
+ synchronized (mLock) {
+ if (hadPrintService(userState, packageName)) {
+ userState.updateIfNeededLocked();
+ }
+ }
+
+ userState.prunePrintServices();
}
@Override
@@ -601,7 +699,7 @@
boolean stoppedSomePackages = false;
List<PrintServiceInfo> enabledServices = userState
- .getEnabledPrintServices();
+ .getPrintServices(PrintManager.ENABLED_SERVICES);
if (enabledServices == null) {
return false;
}
@@ -630,21 +728,11 @@
@Override
public void onPackageAdded(String packageName, int uid) {
if (!mUserManager.isUserUnlocked(getChangingUserId())) return;
-
- // A background user/profile's print jobs are running but there is
- // no UI shown. Hence, if the packages of such a user change we need
- // to handle it as the change may affect ongoing print jobs.
- Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
- intent.setPackage(packageName);
-
- List<ResolveInfo> installedServices = mContext.getPackageManager()
- .queryIntentServicesAsUser(intent,
- GET_SERVICES | MATCH_DEBUG_TRIAGED_MISSING,
- getChangingUserId());
-
- if (installedServices != null) {
- UserState userState = getOrCreateUserStateLocked(getChangingUserId());
- userState.updateIfNeededLocked();
+ synchronized (mLock) {
+ if (hasPrintService(packageName)) {
+ UserState userState = getOrCreateUserStateLocked(getChangingUserId());
+ userState.updateIfNeededLocked();
+ }
}
}
};
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index d179b95..e1d8c6c 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -36,6 +36,7 @@
import android.print.IPrintSpoolerClient;
import android.print.PrintJobId;
import android.print.PrintJobInfo;
+import android.print.PrintManager;
import android.print.PrinterId;
import android.printservice.PrintService;
import android.util.Slog;
@@ -115,8 +116,8 @@
mCallbacks = callbacks;
mClient = new PrintSpoolerClient(this);
mIntent = new Intent();
- mIntent.setComponent(new ComponentName("com.android.printspooler",
- "com.android.printspooler.model.PrintSpoolerService"));
+ mIntent.setComponent(new ComponentName(PrintManager.PRINT_SPOOLER_PACKAGE_NAME,
+ PrintManager.PRINT_SPOOLER_PACKAGE_NAME + ".model.PrintSpoolerService"));
}
public final List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, int state,
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index fcf2fc8..f2f555b 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -44,6 +44,7 @@
import android.os.UserHandle;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintJobStateChangeListener;
+import android.print.IPrintServicesChangeListener;
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintAttributes;
import android.print.PrintJobId;
@@ -121,6 +122,8 @@
private List<PrintJobStateChangeListenerRecord> mPrintJobStateChangeListenerRecords;
+ private List<PrintServicesChangeListenerRecord> mPrintServicesChangeListenerRecords;
+
private boolean mDestroyed;
public UserState(Context context, int userId, Object lock) {
@@ -342,29 +345,63 @@
mSpooler.setPrintJobState(printJobId, PrintJobInfo.STATE_QUEUED, null);
}
- public @Nullable List<PrintServiceInfo> getEnabledPrintServices() {
+ public @Nullable List<PrintServiceInfo> getPrintServices(int selectionFlags) {
synchronized (mLock) {
- List<PrintServiceInfo> enabledServices = null;
+ List<PrintServiceInfo> selectedServices = null;
final int installedServiceCount = mInstalledServices.size();
for (int i = 0; i < installedServiceCount; i++) {
PrintServiceInfo installedService = mInstalledServices.get(i);
+
ComponentName componentName = new ComponentName(
installedService.getResolveInfo().serviceInfo.packageName,
installedService.getResolveInfo().serviceInfo.name);
- if (mActiveServices.containsKey(componentName)) {
- if (enabledServices == null) {
- enabledServices = new ArrayList<PrintServiceInfo>();
+
+ // Update isEnabled under the same lock the final returned list is created
+ installedService.setIsEnabled(mActiveServices.containsKey(componentName));
+
+ if (installedService.isEnabled()) {
+ if ((selectionFlags & PrintManager.ENABLED_SERVICES) == 0) {
+ continue;
}
- enabledServices.add(installedService);
+ } else {
+ if ((selectionFlags & PrintManager.DISABLED_SERVICES) == 0) {
+ continue;
+ }
}
+
+ if (selectedServices == null) {
+ selectedServices = new ArrayList<>();
+ }
+ selectedServices.add(installedService);
}
- return enabledServices;
+ return selectedServices;
}
}
- public List<PrintServiceInfo> getInstalledPrintServices() {
+ public void setPrintServiceEnabled(@NonNull ComponentName serviceName, boolean isEnabled) {
synchronized (mLock) {
- return mInstalledServices;
+ boolean isChanged = false;
+ if (isEnabled) {
+ isChanged = mDisabledServices.remove(serviceName);
+ } else {
+ // Make sure to only disable services that are currently installed
+ final int numServices = mInstalledServices.size();
+ for (int i = 0; i < numServices; i++) {
+ PrintServiceInfo service = mInstalledServices.get(i);
+
+ if (service.getComponentName().equals(serviceName)) {
+ mDisabledServices.add(serviceName);
+ isChanged = true;
+ break;
+ }
+ }
+ }
+
+ if (isChanged) {
+ writeDisabledPrintServicesLocked(mDisabledServices);
+
+ onConfigurationChangedLocked();
+ }
}
}
@@ -523,6 +560,44 @@
}
}
+ public void addPrintServicesChangeListener(@NonNull IPrintServicesChangeListener listener)
+ throws RemoteException {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ if (mPrintServicesChangeListenerRecords == null) {
+ mPrintServicesChangeListenerRecords = new ArrayList<>();
+ }
+ mPrintServicesChangeListenerRecords.add(
+ new PrintServicesChangeListenerRecord(listener) {
+ @Override
+ public void onBinderDied() {
+ mPrintServicesChangeListenerRecords.remove(this);
+ }
+ });
+ }
+ }
+
+ public void removePrintServicesChangeListener(@NonNull IPrintServicesChangeListener listener) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ if (mPrintServicesChangeListenerRecords == null) {
+ return;
+ }
+ final int recordCount = mPrintServicesChangeListenerRecords.size();
+ for (int i = 0; i < recordCount; i++) {
+ PrintServicesChangeListenerRecord record =
+ mPrintServicesChangeListenerRecords.get(i);
+ if (record.listener.asBinder().equals(listener.asBinder())) {
+ mPrintServicesChangeListenerRecords.remove(i);
+ break;
+ }
+ }
+ if (mPrintServicesChangeListenerRecords.isEmpty()) {
+ mPrintServicesChangeListenerRecords = null;
+ }
+ }
+ }
+
@Override
public void onPrintJobStateChanged(PrintJobInfo printJob) {
mPrintJobForAppCache.onPrintJobStateChanged(printJob);
@@ -530,6 +605,10 @@
printJob.getAppId(), 0, printJob.getId()).sendToTarget();
}
+ public void onPrintServicesChanged() {
+ mHandler.obtainMessage(UserStateHandler.MSG_DISPATCH_PRINT_SERVICES_CHANGED).sendToTarget();
+ }
+
@Override
public void onPrintersAdded(List<PrinterInfo> printers) {
synchronized (mLock) {
@@ -894,6 +973,8 @@
iterator.remove();
}
}
+
+ onPrintServicesChanged();
}
private void addServiceLocked(RemotePrintService service) {
@@ -978,8 +1059,29 @@
}
}
+ private void handleDispatchPrintServicesChanged() {
+ final List<PrintServicesChangeListenerRecord> records;
+ synchronized (mLock) {
+ if (mPrintServicesChangeListenerRecords == null) {
+ return;
+ }
+ records = new ArrayList<>(mPrintServicesChangeListenerRecords);
+ }
+ final int recordCount = records.size();
+ for (int i = 0; i < recordCount; i++) {
+ PrintServicesChangeListenerRecord record = records.get(i);
+
+ try {
+ record.listener.onPrintServicesChanged();;
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error notifying for print services change", re);
+ }
+ }
+ }
+
private final class UserStateHandler extends Handler {
public static final int MSG_DISPATCH_PRINT_JOB_STATE_CHANGED = 1;
+ public static final int MSG_DISPATCH_PRINT_SERVICES_CHANGED = 2;
public UserStateHandler(Looper looper) {
super(looper, null, false);
@@ -987,10 +1089,17 @@
@Override
public void handleMessage(Message message) {
- if (message.what == MSG_DISPATCH_PRINT_JOB_STATE_CHANGED) {
- PrintJobId printJobId = (PrintJobId) message.obj;
- final int appId = message.arg1;
- handleDispatchPrintJobStateChanged(printJobId, appId);
+ switch (message.what) {
+ case MSG_DISPATCH_PRINT_JOB_STATE_CHANGED:
+ PrintJobId printJobId = (PrintJobId) message.obj;
+ final int appId = message.arg1;
+ handleDispatchPrintJobStateChanged(printJobId, appId);
+ break;
+ case MSG_DISPATCH_PRINT_SERVICES_CHANGED:
+ handleDispatchPrintServicesChanged();
+ break;
+ default:
+ // not reached
}
}
}
@@ -1015,6 +1124,23 @@
public abstract void onBinderDied();
}
+ private abstract class PrintServicesChangeListenerRecord implements DeathRecipient {
+ @NonNull final IPrintServicesChangeListener listener;
+
+ public PrintServicesChangeListenerRecord(@NonNull IPrintServicesChangeListener listener) throws RemoteException {
+ this.listener = listener;
+ listener.asBinder().linkToDeath(this, 0);
+ }
+
+ @Override
+ public void binderDied() {
+ listener.asBinder().unlinkToDeath(this, 0);
+ onBinderDied();
+ }
+
+ public abstract void onBinderDied();
+ }
+
private class PrinterDiscoverySessionMediator {
private final ArrayMap<PrinterId, PrinterInfo> mPrinters =
new ArrayMap<PrinterId, PrinterInfo>();
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 5874429..69f12eb 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -59,14 +59,17 @@
import android.os.MessageQueue;
import android.os.Messenger;
import android.os.MessageQueue.IdleHandler;
+import android.os.SystemClock;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import android.util.LogPrinter;
+import com.android.internal.util.WakeupMessage;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkMonitor;
+import com.android.server.net.NetworkPinner;
import java.net.InetAddress;
import java.util.concurrent.CountDownLatch;
@@ -87,10 +90,30 @@
private BroadcastInterceptingContext mServiceContext;
private WrappedConnectivityService mService;
- private ConnectivityManager mCm;
+ private WrappedConnectivityManager mCm;
private MockNetworkAgent mWiFiNetworkAgent;
private MockNetworkAgent mCellNetworkAgent;
+ // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods
+ // do not go through ConnectivityService but talk to netd directly, so they don't automatically
+ // reflect the state of our test ConnectivityService.
+ private class WrappedConnectivityManager extends ConnectivityManager {
+ private Network mFakeBoundNetwork;
+
+ public synchronized boolean bindProcessToNetwork(Network network) {
+ mFakeBoundNetwork = network;
+ return true;
+ }
+
+ public synchronized Network getBoundNetworkForProcess() {
+ return mFakeBoundNetwork;
+ }
+
+ public WrappedConnectivityManager(Context context, ConnectivityService service) {
+ super(context, service);
+ }
+ }
+
private class MockContext extends BroadcastInterceptingContext {
MockContext(Context base) {
super(base);
@@ -484,6 +507,35 @@
}
}
+ private class FakeWakeupMessage extends WakeupMessage {
+ private static final int UNREASONABLY_LONG_WAIT = 1000;
+
+ public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd) {
+ super(context, handler, cmdName, cmd);
+ }
+
+ @Override
+ public void schedule(long when) {
+ long delayMs = when - SystemClock.elapsedRealtime();
+ if (delayMs < 0) delayMs = 0;
+ if (delayMs > UNREASONABLY_LONG_WAIT) {
+ fail("Attempting to send msg more than " + UNREASONABLY_LONG_WAIT +
+ "ms into the future: " + delayMs);
+ }
+ mHandler.sendEmptyMessageDelayed(mCmd, delayMs);
+ }
+
+ @Override
+ public void cancel() {
+ mHandler.removeMessages(mCmd);
+ }
+
+ @Override
+ public void onAlarm() {
+ throw new AssertionError("Should never happen. Update this fake.");
+ }
+ }
+
// NetworkMonitor implementation allowing overriding of Internet connectivity probe result.
private class WrappedNetworkMonitor extends NetworkMonitor {
// HTTP response code fed back to NetworkMonitor for Internet connectivity probe.
@@ -498,6 +550,12 @@
protected int isCaptivePortal() {
return gen204ProbeResult;
}
+
+ @Override
+ protected WakeupMessage makeWakeupMessage(
+ Context context, Handler handler, String cmdName, int cmd) {
+ return new FakeWakeupMessage(context, handler, cmdName, cmd);
+ }
}
private class WrappedConnectivityService extends ConnectivityService {
@@ -575,10 +633,10 @@
int delays = 0;
while (!criteria.get()) {
try {
- Thread.sleep(100);
+ Thread.sleep(50);
} catch (InterruptedException e) {
}
- if (++delays == 5) fail();
+ if (++delays == 10) fail();
}
}
@@ -594,6 +652,8 @@
public void setUp() throws Exception {
super.setUp();
+ NetworkMonitor.SetDefaultLingerTime(120);
+
// InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
// http://b/25897652 .
if (Looper.myLooper() == null) {
@@ -607,7 +667,8 @@
mock(INetworkPolicyManager.class));
mService.systemReady();
- mCm = new ConnectivityManager(getContext(), mService);
+ mCm = new WrappedConnectivityManager(getContext(), mService);
+ mCm.bindProcessToNetwork(null);
}
private int transportToLegacyType(int transport) {
@@ -674,8 +735,6 @@
@LargeTest
public void testLingering() throws Exception {
- // Decrease linger timeout to the minimum allowed by AlarmManagerService.
- NetworkMonitor.SetDefaultLingerTime(5000);
verifyNoNetwork();
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -702,10 +761,8 @@
assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) ||
mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork()));
// Test cellular linger timeout.
- try {
- Thread.sleep(6000);
- } catch (InterruptedException e) {
- }
+ waitFor(new Criteria() {
+ public boolean get() { return mCm.getAllNetworks().length == 1; } });
verifyActiveNetwork(TRANSPORT_WIFI);
assertEquals(1, mCm.getAllNetworks().length);
assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());
@@ -1543,4 +1600,103 @@
String url = mCm.getCaptivePortalServerUrl();
assertEquals("http://connectivitycheck.gstatic.com/generate_204", url);
}
+
+ private static class TestNetworkPinner extends NetworkPinner {
+ public static boolean awaitPin(int timeoutMs) {
+ synchronized(sLock) {
+ if (sNetwork == null) {
+ try {
+ sLock.wait(timeoutMs);
+ } catch (InterruptedException e) {}
+ }
+ return sNetwork != null;
+ }
+ }
+
+ public static boolean awaitUnpin(int timeoutMs) {
+ synchronized(sLock) {
+ if (sNetwork != null) {
+ try {
+ sLock.wait(timeoutMs);
+ } catch (InterruptedException e) {}
+ }
+ return sNetwork == null;
+ }
+ }
+ }
+
+ private void assertPinnedToWifiWithCellDefault() {
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
+ assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ }
+
+ private void assertPinnedToWifiWithWifiDefault() {
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ }
+
+ private void assertNotPinnedToWifi() {
+ assertNull(mCm.getBoundNetworkForProcess());
+ assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ }
+
+ @SmallTest
+ public void testNetworkPinner() {
+ NetworkRequest wifiRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI)
+ .build();
+ assertNull(mCm.getBoundNetworkForProcess());
+
+ TestNetworkPinner.pin(mServiceContext, wifiRequest);
+ assertNull(mCm.getBoundNetworkForProcess());
+
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false);
+
+ // When wi-fi connects, expect to be pinned.
+ assertTrue(TestNetworkPinner.awaitPin(100));
+ assertPinnedToWifiWithCellDefault();
+
+ // Disconnect and expect the pin to drop.
+ mWiFiNetworkAgent.disconnect();
+ assertTrue(TestNetworkPinner.awaitUnpin(100));
+ assertNotPinnedToWifi();
+
+ // Reconnecting does not cause the pin to come back.
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false);
+ assertFalse(TestNetworkPinner.awaitPin(100));
+ assertNotPinnedToWifi();
+
+ // Pinning while connected causes the pin to take effect immediately.
+ TestNetworkPinner.pin(mServiceContext, wifiRequest);
+ assertTrue(TestNetworkPinner.awaitPin(100));
+ assertPinnedToWifiWithCellDefault();
+
+ // Explicitly unpin and expect to use the default network again.
+ TestNetworkPinner.unpin();
+ assertNotPinnedToWifi();
+
+ // Disconnect cell and wifi.
+ ConditionVariable cv = waitForConnectivityBroadcasts(3); // cell down, wifi up, wifi down.
+ mCellNetworkAgent.disconnect();
+ mWiFiNetworkAgent.disconnect();
+ waitFor(cv);
+
+ // Pinning takes effect even if the pinned network is the default when the pin is set...
+ TestNetworkPinner.pin(mServiceContext, wifiRequest);
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false);
+ assertTrue(TestNetworkPinner.awaitPin(100));
+ assertPinnedToWifiWithWifiDefault();
+
+ // ... and is maintained even when that network is no longer the default.
+ cv = waitForConnectivityBroadcasts(1);
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mCellNetworkAgent.connect(true);
+ waitFor(cv);
+ assertPinnedToWifiWithCellDefault();
+ }
}
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/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 8b250f4..8da1785 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -437,7 +437,7 @@
return false;
}
} catch (RemoteException re) {
- return false;
+ throw re.rethrowFromSystemServer();
}
final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -805,6 +805,7 @@
return false;
}
} catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
if (isActiveDeviceAdmin(packageName, userId)) {
@@ -849,7 +850,7 @@
}
apps = slice.getList();
} catch (RemoteException e) {
- return new int[0];
+ throw e.rethrowFromSystemServer();
}
// State of each uid. Key is the uid. Value lower 16 bits is the number of apps
@@ -1258,7 +1259,7 @@
userId = ActivityManagerNative.getDefault().handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, true, "isAppInactive", null);
} catch (RemoteException re) {
- return false;
+ throw re.rethrowFromSystemServer();
}
final long token = Binder.clearCallingIdentity();
try {
@@ -1277,7 +1278,7 @@
Binder.getCallingPid(), callingUid, userId, false, true,
"setAppIdle", null);
} catch (RemoteException re) {
- return;
+ throw re.rethrowFromSystemServer();
}
getContext().enforceCallingPermission(Manifest.permission.CHANGE_APP_IDLE_STATE,
"No permission to change app idle state");
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.jpg b/tests/HwAccelerationTest/res/drawable/default_wallpaper.jpg
deleted file mode 100644
index 5acad94..0000000
--- a/tests/HwAccelerationTest/res/drawable/default_wallpaper.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/default_wallpaper.png b/tests/HwAccelerationTest/res/drawable/default_wallpaper.png
new file mode 100644
index 0000000..187a6c0
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable/default_wallpaper.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/layout/projection_clipping.xml b/tests/HwAccelerationTest/res/layout/projection_clipping.xml
index 1f2b939..1ea9f9c 100644
--- a/tests/HwAccelerationTest/res/layout/projection_clipping.xml
+++ b/tests/HwAccelerationTest/res/layout/projection_clipping.xml
@@ -3,24 +3,32 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <FrameLayout
+ <ScrollView
+ android:orientation="vertical"
android:translationX="50dp"
android:translationY="50dp"
android:elevation="30dp"
android:layout_width="200dp"
android:layout_height="200dp"
android:background="@drawable/round_rect_background">
- <View
- android:id="@+id/clickable1"
- android:layout_width="100dp"
- android:layout_height="100dp"
- android:background="?android:attr/selectableItemBackgroundBorderless"/>
- <View
- android:id="@+id/clickable2"
- android:translationX="50dp"
- android:translationY="10dp"
- android:layout_width="150dp"
- android:layout_height="100dp"
- android:background="?android:attr/selectableItemBackgroundBorderless"/>
- </FrameLayout>
+ <FrameLayout
+ android:layout_width="200dp"
+ android:layout_height="wrap_content">
+ <View
+ android:layout_width="200dp"
+ android:layout_height="2000dp"/>
+ <View
+ android:id="@+id/clickable1"
+ android:layout_width="100dp"
+ android:layout_height="100dp"
+ android:background="?android:attr/selectableItemBackgroundBorderless"/>
+ <View
+ android:id="@+id/clickable2"
+ android:translationX="50dp"
+ android:translationY="10dp"
+ android:layout_width="150dp"
+ android:layout_height="100dp"
+ android:background="?android:attr/selectableItemBackgroundBorderless"/>
+ </FrameLayout>
+ </ScrollView>
</LinearLayout>
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/Android.mk b/tools/aapt2/Android.mk
index f9d35ab..57a7692 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -13,15 +13,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-
-# This tool is prebuilt if we're doing an app-only build.
-ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),)
+LOCAL_PATH:= $(call my-dir)
# ==========================================================
# Setup some common variables for the different build
# targets here.
# ==========================================================
-LOCAL_PATH:= $(call my-dir)
main := Main.cpp
sources := \
@@ -192,4 +189,6 @@
include $(BUILD_HOST_EXECUTABLE)
-endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
+ifeq ($(ONE_SHOT_MAKEFILE),)
+include $(call all-makefiles-under,$(LOCAL_PATH))
+endif
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/aapt2/Resource.h b/tools/aapt2/Resource.h
index c71e249..4d1db5b 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -81,9 +81,6 @@
ResourceName(const StringPiece16& p, ResourceType t, const StringPiece16& e);
bool isValid() const;
- bool operator<(const ResourceName& rhs) const;
- bool operator==(const ResourceName& rhs) const;
- bool operator!=(const ResourceName& rhs) const;
std::u16string toString() const;
};
@@ -109,10 +106,6 @@
ResourceName toResourceName() const;
bool isValid() const;
-
- bool operator<(const ResourceNameRef& rhs) const;
- bool operator==(const ResourceNameRef& rhs) const;
- bool operator!=(const ResourceNameRef& rhs) const;
};
/**
@@ -138,17 +131,11 @@
uint8_t packageId() const;
uint8_t typeId() const;
uint16_t entryId() const;
- bool operator<(const ResourceId& rhs) const;
- bool operator==(const ResourceId& rhs) const;
};
struct SourcedResourceName {
ResourceName name;
size_t line;
-
- inline bool operator==(const SourcedResourceName& rhs) const {
- return name == rhs.name && line == rhs.line;
- }
};
struct ResourceFile {
@@ -227,16 +214,23 @@
return static_cast<uint16_t>(id);
}
-inline bool ResourceId::operator<(const ResourceId& rhs) const {
- return id < rhs.id;
+inline bool operator<(const ResourceId& lhs, const ResourceId& rhs) {
+ return lhs.id < rhs.id;
}
-inline bool ResourceId::operator==(const ResourceId& rhs) const {
- return id == rhs.id;
+inline bool operator>(const ResourceId& lhs, const ResourceId& rhs) {
+ return lhs.id > rhs.id;
}
-inline ::std::ostream& operator<<(::std::ostream& out,
- const ResourceId& resId) {
+inline bool operator==(const ResourceId& lhs, const ResourceId& rhs) {
+ return lhs.id == rhs.id;
+}
+
+inline bool operator!=(const ResourceId& lhs, const ResourceId& rhs) {
+ return lhs.id != rhs.id;
+}
+
+inline ::std::ostream& operator<<(::std::ostream& out, const ResourceId& resId) {
std::ios_base::fmtflags oldFlags = out.flags();
char oldFill = out.fill();
out << "0x" << std::internal << std::setfill('0') << std::setw(8)
@@ -266,29 +260,21 @@
return !package.empty() && !entry.empty();
}
-inline bool ResourceName::operator<(const ResourceName& rhs) const {
- return std::tie(package, type, entry)
+inline bool operator<(const ResourceName& lhs, const ResourceName& rhs) {
+ return std::tie(lhs.package, lhs.type, lhs.entry)
< std::tie(rhs.package, rhs.type, rhs.entry);
}
-inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
- return ResourceNameRef(lhs) < b;
-}
-
-inline bool ResourceName::operator==(const ResourceName& rhs) const {
- return std::tie(package, type, entry)
+inline bool operator==(const ResourceName& lhs, const ResourceName& rhs) {
+ return std::tie(lhs.package, lhs.type, lhs.entry)
== std::tie(rhs.package, rhs.type, rhs.entry);
}
-inline bool ResourceName::operator!=(const ResourceName& rhs) const {
- return std::tie(package, type, entry)
+inline bool operator!=(const ResourceName& lhs, const ResourceName& rhs) {
+ return std::tie(lhs.package, lhs.type, lhs.entry)
!= std::tie(rhs.package, rhs.type, rhs.entry);
}
-inline bool operator!=(const ResourceName& lhs, const ResourceNameRef& rhs) {
- return ResourceNameRef(lhs) != rhs;
-}
-
inline std::u16string ResourceName::toString() const {
std::u16string result;
if (!package.empty()) {
@@ -333,18 +319,18 @@
return !package.empty() && !entry.empty();
}
-inline bool ResourceNameRef::operator<(const ResourceNameRef& rhs) const {
- return std::tie(package, type, entry)
+inline bool operator<(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
+ return std::tie(lhs.package, lhs.type, lhs.entry)
< std::tie(rhs.package, rhs.type, rhs.entry);
}
-inline bool ResourceNameRef::operator==(const ResourceNameRef& rhs) const {
- return std::tie(package, type, entry)
+inline bool operator==(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
+ return std::tie(lhs.package, lhs.type, lhs.entry)
== std::tie(rhs.package, rhs.type, rhs.entry);
}
-inline bool ResourceNameRef::operator!=(const ResourceNameRef& rhs) const {
- return std::tie(package, type, entry)
+inline bool operator!=(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
+ return std::tie(lhs.package, lhs.type, lhs.entry)
!= std::tie(rhs.package, rhs.type, rhs.entry);
}
@@ -355,6 +341,18 @@
return out << name.type << "/" << name.entry;
}
+inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
+ return ResourceNameRef(lhs) < b;
+}
+
+inline bool operator!=(const ResourceName& lhs, const ResourceNameRef& rhs) {
+ return ResourceNameRef(lhs) != rhs;
+}
+
+inline bool operator==(const SourcedResourceName& lhs, const SourcedResourceName& rhs) {
+ return lhs.name == rhs.name && lhs.line == rhs.line;
+}
+
} // namespace aapt
#endif // AAPT_RESOURCE_H
diff --git a/tools/aapt2/compile/Compile.cpp b/tools/aapt2/compile/Compile.cpp
index 5f9719e..2452a1d 100644
--- a/tools/aapt2/compile/Compile.cpp
+++ b/tools/aapt2/compile/Compile.cpp
@@ -422,10 +422,6 @@
}
class CompileContext : public IAaptContext {
-private:
- StdErrDiagnostics mDiagnostics;
- bool mVerbose = false;
-
public:
void setVerbose(bool val) {
mVerbose = val;
@@ -444,18 +440,24 @@
return nullptr;
}
- StringPiece16 getCompilationPackage() override {
- return {};
+ const std::u16string& getCompilationPackage() override {
+ static std::u16string empty;
+ return empty;
}
uint8_t getPackageId() override {
return 0x0;
}
- ISymbolTable* getExternalSymbols() override {
+ SymbolTable* getExternalSymbols() override {
abort();
return nullptr;
}
+
+private:
+ StdErrDiagnostics mDiagnostics;
+ bool mVerbose = false;
+
};
/**
diff --git a/tools/aapt2/data/AndroidManifest.xml b/tools/aapt2/data/AndroidManifest.xml
deleted file mode 100644
index d3b2fbe..0000000
--- a/tools/aapt2/data/AndroidManifest.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.app">
- <application
- android:name=".ActivityMain">
- </application>
-</manifest>
diff --git a/tools/aapt2/data/Makefile b/tools/aapt2/data/Makefile
deleted file mode 100644
index 37012de..0000000
--- a/tools/aapt2/data/Makefile
+++ /dev/null
@@ -1,61 +0,0 @@
-##
-# Environment dependent variables
-##
-
-AAPT := aapt2
-ZIPALIGN := zipalign -f 4
-FRAMEWORK := ../../../../../out/target/common/obj/APPS/framework-res_intermediates/package-export.apk
-
-##
-# Project depenedent variables
-##
-
-LOCAL_PACKAGE := com.android.app
-LOCAL_RESOURCE_DIR := res
-LOCAL_LIBS := lib/out/package.apk
-LOCAL_OUT := out
-LOCAL_GEN := out/gen
-LOCAL_PROGUARD := out/proguard.rule
-
-##
-# AAPT2 custom rules.
-##
-
-PRIVATE_R_FILE := $(LOCAL_GEN)/$(subst .,/,$(LOCAL_PACKAGE))/R.java
-$(info PRIVATE_R_FILE = $(PRIVATE_R_FILE))
-
-# Eg: framework.apk, etc.
-PRIVATE_INCLUDES := $(FRAMEWORK)
-$(info PRIVATE_INCLUDES = $(PRIVATE_INCLUDES))
-
-# Eg: res/drawable/icon.png, res/values/styles.xml
-PRIVATE_RESOURCES := $(shell find $(LOCAL_RESOURCE_DIR) -mindepth 1 -maxdepth 2 -type f)
-$(info PRIVATE_RESOURCES = $(PRIVATE_RESOURCES))
-
-PRIVATE_RESOURCE_OBJECTS := $(subst /,_,$(patsubst $(LOCAL_RESOURCE_DIR)/%,%,$(filter $(LOCAL_RESOURCE_DIR)/values%,$(PRIVATE_RESOURCES))))
-PRIVATE_RESOURCE_OBJECTS := $(addprefix $(LOCAL_OUT)/,$(PRIVATE_RESOURCE_OBJECTS:.xml=.arsc.flat))
-$(info PRIVATE_RESOURCE_OBJECTS = $(PRIVATE_RESOURCE_OBJECTS))
-
-PRIVATE_FILE_OBJECTS := $(subst /,_,$(patsubst $(LOCAL_RESOURCE_DIR)/%,%,$(filter-out $(LOCAL_RESOURCE_DIR)/values%,$(PRIVATE_RESOURCES))))
-PRIVATE_FILE_OBJECTS := $(addprefix $(LOCAL_OUT)/,$(addsuffix .flat,$(PRIVATE_FILE_OBJECTS)))
-$(info PRIVATE_FILE_OBJECTS = $(PRIVATE_FILE_OBJECTS))
-
-.SECONDEXPANSION:
-
-$(LOCAL_OUT)/%.arsc.flat: $(LOCAL_RESOURCE_DIR)/$$(subst _,/,%).xml
- $(AAPT) compile -o $(LOCAL_OUT) $<
-
-$(LOCAL_OUT)/%.flat: $(LOCAL_RESOURCE_DIR)/$$(subst _,/,%)
- $(AAPT) compile -o $(LOCAL_OUT) $<
-
-$(LOCAL_PROGUARD) $(LOCAL_OUT)/package.apk: AndroidManifest.xml
-$(PRIVATE_R_FILE) $(LOCAL_PROGUARD) $(LOCAL_OUT)/package.apk: $(PRIVATE_FILE_OBJECTS) $(PRIVATE_RESOURCE_OBJECTS)
- $(AAPT) link -o $(LOCAL_OUT)/package.apk --manifest AndroidManifest.xml --java $(LOCAL_GEN) --proguard $(LOCAL_PROGUARD) -I $(PRIVATE_INCLUDES) $(filter-out AndroidManifest.xml,$^) -v
-
-# Create the out directory if needed.
-dummy := $(shell test -d $(LOCAL_OUT) || mkdir -p $(LOCAL_OUT))
-
-.PHONY: all
-all: $(LOCAL_OUT)/package.apk $(LOCAL_PROGUARD) $(PRIVATE_R_FILE)
-
-.DEFAULT_GOAL := all
diff --git a/tools/aapt2/data/lib/AndroidManifest.xml b/tools/aapt2/data/lib/AndroidManifest.xml
deleted file mode 100644
index 08b468e..0000000
--- a/tools/aapt2/data/lib/AndroidManifest.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.appcompat">
-
- <uses-feature android:name="bloooop" />
-</manifest>
diff --git a/tools/aapt2/data/lib/Makefile b/tools/aapt2/data/lib/Makefile
deleted file mode 100644
index 741be9a..0000000
--- a/tools/aapt2/data/lib/Makefile
+++ /dev/null
@@ -1,81 +0,0 @@
-##
-# Environment dependent variables
-##
-
-AAPT := aapt2
-ZIPALIGN := zipalign -f 4
-FRAMEWORK := ../../../../../../out/target/common/obj/APPS/framework-res_intermediates/package-export.apk
-
-##
-# Project depenedent variables
-##
-
-LOCAL_PACKAGE := android.appcompat
-LOCAL_RESOURCE_DIR := res
-LOCAL_OUT := out
-LOCAL_GEN := out/gen
-
-##
-# AAPT2 custom rules.
-##
-
-PRIVATE_APK_UNALIGNED := $(LOCAL_OUT)/package-unaligned.apk
-PRIVATE_APK_ALIGNED := $(LOCAL_OUT)/package.apk
-
-# Eg: framework.apk, etc.
-PRIVATE_LIBS := $(FRAMEWORK)
-$(info PRIVATE_LIBS = $(PRIVATE_LIBS))
-
-# Eg: gen/com/android/app/R.java
-PRIVATE_R_JAVA := $(LOCAL_GEN)/$(subst .,/,$(LOCAL_PACKAGE))/R.java
-$(info PRIVATE_R_JAVA = $(PRIVATE_R_JAVA))
-
-# Eg: res/drawable/icon.png, res/values/styles.xml
-PRIVATE_RESOURCES := $(shell find $(LOCAL_RESOURCE_DIR) -mindepth 1 -maxdepth 2 -type f)
-$(info PRIVATE_RESOURCES = $(PRIVATE_RESOURCES))
-
-# Eg: drawable, values, layouts
-PRIVATE_RESOURCE_TYPES := \
- $(patsubst $(LOCAL_RESOURCE_DIR)/%/,%,$(sort $(dir $(PRIVATE_RESOURCES))))
-$(info PRIVATE_RESOURCE_TYPES = $(PRIVATE_RESOURCE_TYPES))
-
-# Eg: out/values-v4.apk, out/drawable-xhdpi.apk
-PRIVATE_INTERMEDIATE_TABLES := $(patsubst %,$(LOCAL_OUT)/%.apk,$(PRIVATE_RESOURCE_TYPES))
-$(info PRIVATE_INTERMEDIATE_TABLES = $(PRIVATE_INTERMEDIATE_TABLES))
-
-# Generates rules for collect phase.
-# $1: Resource type (values-v4)
-# returns: out/values-v4.apk: res/values-v4/styles.xml res/values-v4/colors.xml
-define make-collect-rule
-$(LOCAL_OUT)/$1.apk: $(filter $(LOCAL_RESOURCE_DIR)/$1/%,$(PRIVATE_RESOURCES))
- $(AAPT) compile -o $$@ $$^
-endef
-
-# Collect: out/values-v4.apk <- res/values-v4/styles.xml res/values-v4/colors.xml
-$(foreach d,$(PRIVATE_RESOURCE_TYPES),$(eval $(call make-collect-rule,$d)))
-
-# Link: out/package-unaligned.apk <- out/values-v4.apk out/drawable-v4.apk
-$(PRIVATE_APK_UNALIGNED): $(PRIVATE_INTERMEDIATE_TABLES) $(PRIVATE_LIBS) AndroidManifest.xml
- $(AAPT) link --manifest AndroidManifest.xml $(addprefix -I ,$(PRIVATE_LIBS)) --java $(LOCAL_GEN) -o $@ $(PRIVATE_INTERMEDIATE_TABLES) --static-lib
-
-# R.java: gen/com/android/app/R.java <- out/resources.arsc
-# No action since R.java is generated when out/resources.arsc is.
-$(PRIVATE_R_JAVA): $(PRIVATE_APK_UNALIGNED)
-
-# Assemble: zip out/resources.arsc AndroidManifest.xml and res/**/*
-$(PRIVATE_APK_ALIGNED): $(PRIVATE_APK_UNALIGNED)
- $(ZIPALIGN) $< $@
-
-# Create the out directory if needed.
-dummy := $(shell test -d $(LOCAL_OUT) || mkdir -p $(LOCAL_OUT))
-
-.PHONY: java
-java: $(PRIVATE_R_JAVA)
-
-.PHONY: assemble
-assemble: $(PRIVATE_APK_ALIGNED)
-
-.PHONY: all
-all: assemble java
-
-.DEFAULT_GOAL := all
diff --git a/tools/aapt2/data/lib/res/layout/main.xml b/tools/aapt2/data/lib/res/layout/main.xml
deleted file mode 100644
index 187ed2d..0000000
--- a/tools/aapt2/data/lib/res/layout/main.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
diff --git a/tools/aapt2/data/lib/res/raw/hello.txt b/tools/aapt2/data/lib/res/raw/hello.txt
deleted file mode 100644
index 44fc22b..0000000
--- a/tools/aapt2/data/lib/res/raw/hello.txt
+++ /dev/null
@@ -1 +0,0 @@
-Oh howdy there
diff --git a/tools/aapt2/data/lib/res/values/styles.xml b/tools/aapt2/data/lib/res/values/styles.xml
deleted file mode 100644
index 4ce6333..0000000
--- a/tools/aapt2/data/lib/res/values/styles.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <style name="Platform.AppCompat" parent="@android:style/Theme">
- <item name="android:windowNoTitle">true</item>
- </style>
-
- <bool name="allow">true</bool>
-</resources>
diff --git a/tools/aapt2/data/res/drawable/image.xml b/tools/aapt2/data/res/drawable/image.xml
deleted file mode 100644
index 9b38739..0000000
--- a/tools/aapt2/data/res/drawable/image.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<vector />
diff --git a/tools/aapt2/data/res/layout-v21/main.xml b/tools/aapt2/data/res/layout-v21/main.xml
deleted file mode 100644
index 959b349..0000000
--- a/tools/aapt2/data/res/layout-v21/main.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:support="http://schemas.android.com/apk/res/android.appcompat"
- android:id="@+id/view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-</LinearLayout>
diff --git a/tools/aapt2/data/res/layout/main.xml b/tools/aapt2/data/res/layout/main.xml
deleted file mode 100644
index 8a5e9e8..0000000
--- a/tools/aapt2/data/res/layout/main.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:support="http://schemas.android.com/apk/res/android.appcompat"
- android:id="@+id/view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <fragment class="android.test.sample.App$Inner" />
-
- <variable name="user" type="com.android.User" />
-
- <View xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/me"
- android:layout_width="1dp"
- android:onClick="doClick"
- android:text="@{user.name}"
- android:background="#ffffff"
- android:layout_height="match_parent"
- app:flags="complex|weak"
- android:colorAccent="#ffffff"/>
-</LinearLayout>
diff --git a/tools/aapt2/data/res/values-v4/styles.xml b/tools/aapt2/data/res/values-v4/styles.xml
deleted file mode 100644
index 979a82a..0000000
--- a/tools/aapt2/data/res/values-v4/styles.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <style name="App" parent="android:Theme.Material">
- <item name="android:colorAccent">@color/accent</item>
- <item name="android:text">Hey</item>
- </style>
-</resources>
diff --git a/tools/aapt2/data/res/values/colors.xml b/tools/aapt2/data/res/values/colors.xml
deleted file mode 100644
index 89db5fb..0000000
--- a/tools/aapt2/data/res/values/colors.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <color name="primary">#f44336</color>
- <color name="primary_dark">#b71c1c</color>
- <color name="accent">#fdd835</color>
-</resources>
diff --git a/tools/aapt2/data/res/values/styles.xml b/tools/aapt2/data/res/values/styles.xml
deleted file mode 100644
index 2bbdad1..0000000
--- a/tools/aapt2/data/res/values/styles.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources xmlns:lib="http://schemas.android.com/apk/res/android.appcompat">
- <style name="App">
- <item name="android:background">@color/primary</item>
- <item name="android:colorPrimary">@color/primary</item>
- <item name="android:colorPrimaryDark">@color/primary_dark</item>
- <item name="android:colorAccent">@color/accent</item>
- </style>
- <attr name="custom" format="reference" />
- <style name="Pop">
- <item name="custom">@android:drawable/btn_default</item>
- <item name="android:focusable">true</item>
- </style>
- <string name="yo">@string/wow</string>
-
- <declare-styleable name="View">
- <attr name="custom" />
- <attr name="decor">
- <enum name="no-border" value="0"/>
- <enum name="border" value="1"/>
- <enum name="shadow" value="2"/>
- </attr>
- </declare-styleable>
-
-</resources>
diff --git a/tools/aapt2/data/res/values/test.xml b/tools/aapt2/data/res/values/test.xml
deleted file mode 100644
index d7ab1c8..0000000
--- a/tools/aapt2/data/res/values/test.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hooha"><font bgcolor="#ffffff">Hey guys!</font> <xliff:g>My</xliff:g> name is <b>Adam</b>. How <b><i>are</i></b> you?</string>
- <public name="hooha" type="string" id="0x7f020001"/>
- <string name="wow">@android:string/ok</string>
- <public name="layout_width" type="attr" />
- <attr name="layout_width" format="boolean" />
- <attr name="flags">
- <flag name="complex" value="1" />
- <flag name="pub" value="2" />
- <flag name="weak" value="4" />
- </attr>
-</resources>
diff --git a/tools/aapt2/data/resources.arsc b/tools/aapt2/data/resources.arsc
deleted file mode 100644
index 6a416df..0000000
--- a/tools/aapt2/data/resources.arsc
+++ /dev/null
Binary files differ
diff --git a/tools/aapt2/data/resources_base.arsc b/tools/aapt2/data/resources_base.arsc
deleted file mode 100644
index f9d0610..0000000
--- a/tools/aapt2/data/resources_base.arsc
+++ /dev/null
Binary files differ
diff --git a/tools/aapt2/data/resources_hdpi.arsc b/tools/aapt2/data/resources_hdpi.arsc
deleted file mode 100644
index 97232a3..0000000
--- a/tools/aapt2/data/resources_hdpi.arsc
+++ /dev/null
Binary files differ
diff --git a/tools/aapt2/dump/Dump.cpp b/tools/aapt2/dump/Dump.cpp
index ad7de0a..56b9f9a 100644
--- a/tools/aapt2/dump/Dump.cpp
+++ b/tools/aapt2/dump/Dump.cpp
@@ -17,6 +17,7 @@
#include "Debug.h"
#include "Diagnostics.h"
#include "Flags.h"
+#include "io/ZipArchive.h"
#include "process/IResourceTableConsumer.h"
#include "proto/ProtoSerialize.h"
#include "util/Files.h"
@@ -56,6 +57,35 @@
void tryDumpFile(IAaptContext* context, const std::string& filePath) {
std::string err;
+ std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::create(filePath, &err);
+ if (zip) {
+ io::IFile* file = zip->findFile("resources.arsc.flat");
+ if (file) {
+ std::unique_ptr<io::IData> data = file->openAsData();
+ if (!data) {
+ context->getDiagnostics()->error(DiagMessage(filePath)
+ << "failed to open resources.arsc.flat");
+ return;
+ }
+
+ pb::ResourceTable pbTable;
+ if (!pbTable.ParseFromArray(data->data(), data->size())) {
+ context->getDiagnostics()->error(DiagMessage(filePath)
+ << "invalid resources.arsc.flat");
+ return;
+ }
+
+ std::unique_ptr<ResourceTable> table = deserializeTableFromPb(
+ pbTable, Source(filePath), context->getDiagnostics());
+ if (table) {
+ DebugPrintTableOptions debugPrintTableOptions;
+ debugPrintTableOptions.showSources = true;
+ Debug::printTable(table.get(), debugPrintTableOptions);
+ }
+ }
+ return;
+ }
+
Maybe<android::FileMap> file = file::mmapPath(filePath, &err);
if (!file) {
context->getDiagnostics()->error(DiagMessage(filePath) << err);
@@ -90,15 +120,16 @@
return nullptr;
}
- StringPiece16 getCompilationPackage() override {
- return {};
+ const std::u16string& getCompilationPackage() override {
+ static std::u16string empty;
+ return empty;
}
uint8_t getPackageId() override {
return 0;
}
- ISymbolTable* getExternalSymbols() override {
+ SymbolTable* getExternalSymbols() override {
abort();
return nullptr;
}
diff --git a/tools/aapt2/flatten/XmlFlattener.cpp b/tools/aapt2/flatten/XmlFlattener.cpp
index 8219462..3eac633 100644
--- a/tools/aapt2/flatten/XmlFlattener.cpp
+++ b/tools/aapt2/flatten/XmlFlattener.cpp
@@ -144,9 +144,9 @@
}
static bool cmpXmlAttributeById(const xml::Attribute* a, const xml::Attribute* b) {
- if (a->compiledAttribute) {
- if (b->compiledAttribute) {
- return a->compiledAttribute.value().id < b->compiledAttribute.value().id;
+ if (a->compiledAttribute && a->compiledAttribute.value().id) {
+ if (b->compiledAttribute && b->compiledAttribute.value().id) {
+ return a->compiledAttribute.value().id.value() < b->compiledAttribute.value().id.value();
}
return true;
} else if (!b->compiledAttribute) {
@@ -167,8 +167,8 @@
// Filter the attributes.
for (xml::Attribute& attr : node->attributes) {
- if (mOptions.maxSdkLevel && attr.compiledAttribute) {
- size_t sdkLevel = findAttributeSdkLevel(attr.compiledAttribute.value().id);
+ if (mOptions.maxSdkLevel && attr.compiledAttribute && attr.compiledAttribute.value().id) {
+ size_t sdkLevel = findAttributeSdkLevel(attr.compiledAttribute.value().id.value());
if (sdkLevel > mOptions.maxSdkLevel.value()) {
continue;
}
@@ -191,8 +191,8 @@
uint16_t attributeIndex = 1;
for (const xml::Attribute* xmlAttr : mFilteredAttrs) {
// Assign the indices for specific attributes.
- if (xmlAttr->compiledAttribute &&
- xmlAttr->compiledAttribute.value().id == kIdAttr) {
+ if (xmlAttr->compiledAttribute && xmlAttr->compiledAttribute.value().id &&
+ xmlAttr->compiledAttribute.value().id.value() == kIdAttr) {
flatElem->idIndex = util::hostToDevice16(attributeIndex);
} else if (xmlAttr->namespaceUri.empty()) {
if (xmlAttr->name == u"class") {
@@ -208,7 +208,7 @@
flatAttr->rawValue.index = util::hostToDevice32(-1);
- if (!xmlAttr->compiledAttribute) {
+ if (!xmlAttr->compiledAttribute || !xmlAttr->compiledAttribute.value().id) {
// The attribute has no associated ResourceID, so the string order doesn't matter.
addString(xmlAttr->name, kLowPriority, &flatAttr->name);
} else {
@@ -221,17 +221,17 @@
// Lookup the StringPool for this package and make the reference there.
const xml::AaptAttribute& aaptAttr = xmlAttr->compiledAttribute.value();
- StringPool::Ref nameRef = mPackagePools[aaptAttr.id.packageId()].makeRef(
- xmlAttr->name, StringPool::Context{ aaptAttr.id.id });
+ StringPool::Ref nameRef = mPackagePools[aaptAttr.id.value().packageId()].makeRef(
+ xmlAttr->name, StringPool::Context{ aaptAttr.id.value().id });
// Add it to the list of strings to flatten.
addString(nameRef, &flatAttr->name);
+ }
- if (mOptions.keepRawValues) {
- // Keep raw values (this is for static libraries).
- // TODO(with a smarter inflater for binary XML, we can do without this).
- addString(xmlAttr->value, kLowPriority, &flatAttr->rawValue);
- }
+ if (mOptions.keepRawValues || !xmlAttr->compiledValue) {
+ // Keep raw values if the value is not compiled or
+ // if we're building a static library (need symbols).
+ addString(xmlAttr->value, kLowPriority, &flatAttr->rawValue);
}
if (xmlAttr->compiledValue) {
@@ -240,7 +240,6 @@
} else {
// Flatten as a regular string type.
flatAttr->typedValue.dataType = android::Res_value::TYPE_STRING;
- addString(xmlAttr->value, kLowPriority, &flatAttr->rawValue);
addString(xmlAttr->value, kLowPriority,
(ResStringPool_ref*) &flatAttr->typedValue.data);
}
diff --git a/tools/aapt2/flatten/XmlFlattener_test.cpp b/tools/aapt2/flatten/XmlFlattener_test.cpp
index 8648879..fef5ca3 100644
--- a/tools/aapt2/flatten/XmlFlattener_test.cpp
+++ b/tools/aapt2/flatten/XmlFlattener_test.cpp
@@ -32,7 +32,7 @@
mContext = test::ContextBuilder()
.setCompilationPackage(u"com.app.test")
.setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
- .setSymbolTable(test::StaticSymbolTableBuilder()
+ .addSymbolSource(test::StaticSymbolSourceBuilder()
.addSymbol(u"@android:attr/id", ResourceId(0x010100d0),
test::AttributeBuilder().build())
.addSymbol(u"@com.app.test:id/id", ResourceId(0x7f020000))
diff --git a/tools/aapt2/integration-tests/Android.mk b/tools/aapt2/integration-tests/Android.mk
new file mode 100644
index 0000000..6361f9b
--- /dev/null
+++ b/tools/aapt2/integration-tests/Android.mk
@@ -0,0 +1,2 @@
+LOCAL_PATH := $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/aapt2/integration-tests/AppOne/Android.mk b/tools/aapt2/integration-tests/AppOne/Android.mk
new file mode 100644
index 0000000..bc40a62
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/Android.mk
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_PACKAGE_NAME := AaptTestAppOne
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+ AaptTestStaticLibOne \
+ AaptTestStaticLibTwo
+LOCAL_AAPT_FLAGS := --no-version-vectors
+include $(BUILD_PACKAGE)
diff --git a/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml b/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
new file mode 100644
index 0000000..b6d8f2d
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?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.
+-->
+
+<manifest package="com.android.aapt.app.one" />
diff --git a/tools/aapt2/data/res/drawable/icon.png b/tools/aapt2/integration-tests/AppOne/res/drawable/icon.png
similarity index 100%
rename from tools/aapt2/data/res/drawable/icon.png
rename to tools/aapt2/integration-tests/AppOne/res/drawable/icon.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/image.xml b/tools/aapt2/integration-tests/AppOne/res/drawable/image.xml
new file mode 100644
index 0000000..6132a75
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/image.xml
@@ -0,0 +1,17 @@
+<?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 />
diff --git a/tools/aapt2/data/res/drawable/test.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/test.9.png
similarity index 100%
rename from tools/aapt2/data/res/drawable/test.9.png
rename to tools/aapt2/integration-tests/AppOne/res/drawable/test.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml b/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml
new file mode 100644
index 0000000..9f5a4a8
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:support="http://schemas.android.com/apk/res/android.appcompat"
+ android:id="@+id/view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+</LinearLayout>
diff --git a/tools/aapt2/integration-tests/AppOne/res/layout/main.xml b/tools/aapt2/integration-tests/AppOne/res/layout/main.xml
new file mode 100644
index 0000000..ab1a251
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/layout/main.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:support="http://schemas.android.com/apk/res/android.appcompat"
+ android:id="@+id/view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <fragment class="android.test.sample.App$Inner" />
+
+ <variable name="user" type="com.android.User" />
+
+ <View xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/me"
+ android:layout_width="1dp"
+ android:onClick="doClick"
+ android:text="@{user.name}"
+ android:background="#ffffff"
+ android:layout_height="match_parent"
+ app:flags="complex|weak"
+ android:colorAccent="#ffffff"/>
+</LinearLayout>
diff --git a/tools/aapt2/data/res/raw/test.txt b/tools/aapt2/integration-tests/AppOne/res/raw/test.txt
similarity index 100%
rename from tools/aapt2/data/res/raw/test.txt
rename to tools/aapt2/integration-tests/AppOne/res/raw/test.txt
diff --git a/tools/aapt2/integration-tests/AppOne/res/values-v4/styles.xml b/tools/aapt2/integration-tests/AppOne/res/values-v4/styles.xml
new file mode 100644
index 0000000..d8c11e2
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/values-v4/styles.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.
+-->
+
+<resources>
+ <style name="App" parent="android:Theme.Material">
+ <item name="android:colorAccent">@color/accent</item>
+ <item name="android:text">Hey</item>
+ </style>
+</resources>
diff --git a/tools/aapt2/integration-tests/AppOne/res/values/colors.xml b/tools/aapt2/integration-tests/AppOne/res/values/colors.xml
new file mode 100644
index 0000000..4df5077
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/values/colors.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.
+-->
+
+<resources>
+ <color name="primary">#f44336</color>
+ <color name="primary_dark">#b71c1c</color>
+ <color name="accent">#fdd835</color>
+</resources>
diff --git a/tools/aapt2/integration-tests/AppOne/res/values/styles.xml b/tools/aapt2/integration-tests/AppOne/res/values/styles.xml
new file mode 100644
index 0000000..f05845c
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/values/styles.xml
@@ -0,0 +1,40 @@
+<?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.
+-->
+
+<resources xmlns:lib="http://schemas.android.com/apk/res/android.appcompat">
+ <style name="App">
+ <item name="android:background">@color/primary</item>
+ <item name="android:colorPrimary">@color/primary</item>
+ <item name="android:colorPrimaryDark">@color/primary_dark</item>
+ <item name="android:colorAccent">@color/accent</item>
+ </style>
+ <attr name="custom" format="reference" />
+ <style name="Pop">
+ <item name="custom">@android:drawable/btn_default</item>
+ <item name="android:focusable">true</item>
+ </style>
+ <string name="yo">@string/wow</string>
+
+ <declare-styleable name="View">
+ <attr name="custom" />
+ <attr name="decor">
+ <enum name="no-border" value="0"/>
+ <enum name="border" value="1"/>
+ <enum name="shadow" value="2"/>
+ </attr>
+ </declare-styleable>
+
+</resources>
diff --git a/tools/aapt2/integration-tests/AppOne/res/values/test.xml b/tools/aapt2/integration-tests/AppOne/res/values/test.xml
new file mode 100644
index 0000000..f4b7471
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/values/test.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Reference the two static libraries -->
+ <string name="AppFooBar">@string/FooBar</string>
+ <string name="AppFoo">@string/Foo</string>
+
+ <string name="hooha"><font bgcolor="#ffffff">Hey guys!</font> <xliff:g>My</xliff:g> name is <b>Adam</b>. How <b><i>are</i></b> you?</string>
+ <public name="hooha" type="string" id="0x7f020001"/>
+ <string name="wow">@android:string/ok</string>
+ <public name="layout_width" type="attr" />
+ <attr name="layout_width" format="boolean" />
+ <attr name="flags">
+ <flag name="complex" value="1" />
+ <flag name="pub" value="2" />
+ <flag name="weak" value="4" />
+ </attr>
+</resources>
diff --git a/tools/aapt2/integration-tests/AppOne/src/com/android/aapt/app/one/AppOne.java b/tools/aapt2/integration-tests/AppOne/src/com/android/aapt/app/one/AppOne.java
new file mode 100644
index 0000000..472b35a
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/src/com/android/aapt/app/one/AppOne.java
@@ -0,0 +1,26 @@
+/*
+ * 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.aapt.app.one;
+
+public class AppOne {
+ // IDs from StaticLibOne
+ public static int FooId = com.android.aapt.staticlib.one.R.string.Foo;
+ public static int LayoutId = com.android.aapt.staticlib.one.R.layout.layout;
+
+ // IDs from StaticLibTwo
+ public static int FooBarId = com.android.aapt.staticlib.two.R.string.FooBar;
+}
+
diff --git a/tools/aapt2/integration-tests/StaticLibOne/Android.mk b/tools/aapt2/integration-tests/StaticLibOne/Android.mk
new file mode 100644
index 0000000..d59dc60
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibOne/Android.mk
@@ -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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_MODULE := AaptTestStaticLibOne
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tools/aapt2/integration-tests/StaticLibOne/AndroidManifest.xml b/tools/aapt2/integration-tests/StaticLibOne/AndroidManifest.xml
new file mode 100644
index 0000000..705047e
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibOne/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?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.
+-->
+
+<manifest package="com.android.aapt.staticlib.one" />
diff --git a/tools/aapt2/integration-tests/StaticLibOne/res/layout/layout.xml b/tools/aapt2/integration-tests/StaticLibOne/res/layout/layout.xml
new file mode 100644
index 0000000..683c91c
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibOne/res/layout/layout.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:text="@string/Foo" />
diff --git a/tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml b/tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml
new file mode 100644
index 0000000..2b24544
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibOne/res/values/values.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.
+-->
+
+<resources>
+ <attr name="StaticLibOne_attr" format="string" />
+
+ <string name="Foo">Foo</string>
+ <string name="Foo" product="tablet">Bar</string>
+</resources>
diff --git a/core/java/android/hardware/camera2/utils/LongParcelable.aidl b/tools/aapt2/integration-tests/StaticLibOne/src/com/android/aapt/staticlib/one/StaticLibOne.java
similarity index 64%
copy from core/java/android/hardware/camera2/utils/LongParcelable.aidl
copy to tools/aapt2/integration-tests/StaticLibOne/src/com/android/aapt/staticlib/one/StaticLibOne.java
index 98ad1b2..cf48f67 100644
--- a/core/java/android/hardware/camera2/utils/LongParcelable.aidl
+++ b/tools/aapt2/integration-tests/StaticLibOne/src/com/android/aapt/staticlib/one/StaticLibOne.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.
@@ -13,8 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.aapt.staticlib.one;
-package android.hardware.camera2.utils;
-
-/** @hide */
-parcelable LongParcelable;
+public class StaticLibOne {
+ // IDs from StaticLibOne
+ public static int FooId = com.android.aapt.staticlib.one.R.string.Foo;
+ public static int LayoutId = com.android.aapt.staticlib.one.R.layout.layout;
+}
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/Android.mk b/tools/aapt2/integration-tests/StaticLibTwo/Android.mk
new file mode 100644
index 0000000..8b6eb41
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibTwo/Android.mk
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_MODULE := AaptTestStaticLibTwo
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_SHARED_ANDROID_LIBRARIES := AaptTestStaticLibOne
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/AndroidManifest.xml b/tools/aapt2/integration-tests/StaticLibTwo/AndroidManifest.xml
new file mode 100644
index 0000000..28f0699
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibTwo/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?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.
+-->
+
+<manifest package="com.android.aapt.staticlib.two" />
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/res/drawable/vector.xml b/tools/aapt2/integration-tests/StaticLibTwo/res/drawable/vector.xml
new file mode 100644
index 0000000..dd5979f
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibTwo/res/drawable/vector.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="1123"/>
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/res/layout/layout_two.xml b/tools/aapt2/integration-tests/StaticLibTwo/res/layout/layout_two.xml
new file mode 100644
index 0000000..ba98307
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibTwo/res/layout/layout_two.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+
+<View xmlns:custom="http://schemas.android.com/apk/res-auto"
+ custom:StaticLibOne_attr="@string/FooBar" />
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/res/values/values.xml b/tools/aapt2/integration-tests/StaticLibTwo/res/values/values.xml
new file mode 100644
index 0000000..97bb2a5
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibTwo/res/values/values.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources>
+ <string name="FooBar">@string/Foo</string>
+</resources>
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java b/tools/aapt2/integration-tests/StaticLibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java
new file mode 100644
index 0000000..7110dcd
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java
@@ -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.
+ */
+package com.android.aapt.staticlib.two;
+
+public class StaticLibTwo {
+ // IDs from StaticLibOne
+ public static int FooId = com.android.aapt.staticlib.one.R.string.Foo;
+ public static int LayoutId = com.android.aapt.staticlib.one.R.layout.layout;
+
+ // IDs from StaticLibTwo
+ public static int FooBarId = com.android.aapt.staticlib.two.R.string.FooBar;
+}
diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp
index 329dac9..b3e7a02 100644
--- a/tools/aapt2/io/ZipArchive.cpp
+++ b/tools/aapt2/io/ZipArchive.cpp
@@ -92,9 +92,8 @@
return {};
}
- ZipString suffix(".flat");
void* cookie = nullptr;
- result = StartIteration(collection->mHandle, &cookie, nullptr, &suffix);
+ result = StartIteration(collection->mHandle, &cookie, nullptr, nullptr);
if (result != 0) {
if (outError) *outError = ErrorCodeString(result);
return {};
diff --git a/tools/aapt2/java/ClassDefinitionWriter.h b/tools/aapt2/java/ClassDefinitionWriter.h
index 04e1274..cf92c9a 100644
--- a/tools/aapt2/java/ClassDefinitionWriter.h
+++ b/tools/aapt2/java/ClassDefinitionWriter.h
@@ -65,7 +65,7 @@
<< "String " << name << "=\"" << val << "\";\n";
}
- void addResourceMember(const StringPiece16& name, AnnotationProcessor* processor,
+ void addResourceMember(const StringPiece& name, AnnotationProcessor* processor,
const ResourceId id) {
ensureClassDeclaration();
if (processor) {
@@ -76,7 +76,7 @@
}
template <typename Iterator, typename FieldAccessorFunc>
- void addArrayMember(const StringPiece16& name, AnnotationProcessor* processor,
+ void addArrayMember(const StringPiece& name, AnnotationProcessor* processor,
const Iterator begin, const Iterator end, FieldAccessorFunc f) {
ensureClassDeclaration();
if (processor) {
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 6e340a2..1076ffe 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -68,16 +68,41 @@
* Java symbols can not contain . or -, but those are valid in a resource name.
* Replace those with '_'.
*/
-static std::u16string transform(const StringPiece16& symbol) {
- std::u16string output = symbol.toString();
- for (char16_t& c : output) {
- if (c == u'.' || c == u'-') {
- c = u'_';
+static std::string transform(const StringPiece16& symbol) {
+ std::string output = util::utf16ToUtf8(symbol);
+ for (char& c : output) {
+ if (c == '.' || c == '-') {
+ c = '_';
}
}
return output;
}
+/**
+ * Transforms an attribute in a styleable to the Java field name:
+ *
+ * <declare-styleable name="Foo">
+ * <attr name="android:bar" />
+ * <attr name="bar" />
+ * </declare-styleable>
+ *
+ * Foo_android_bar
+ * Foo_bar
+ */
+static std::string transformNestedAttr(const ResourceNameRef& attrName,
+ const std::string& styleableClassName,
+ const StringPiece16& packageNameToGenerate) {
+ std::string output = styleableClassName;
+
+ // We may reference IDs from other packages, so prefix the entry name with
+ // the package.
+ if (!attrName.package.empty() && packageNameToGenerate != attrName.package) {
+ output += "_" + transform(attrName.package);
+ }
+ output += "_" + transform(attrName.entry);
+ return output;
+}
+
bool JavaClassGenerator::skipSymbol(SymbolState state) {
switch (mOptions.types) {
case JavaClassGeneratorOptions::SymbolTypes::kAll:
@@ -90,48 +115,91 @@
return true;
}
+struct StyleableAttr {
+ const Reference* attrRef;
+ std::string fieldName;
+};
+
+static bool lessStyleableAttr(const StyleableAttr& lhs, const StyleableAttr& rhs) {
+ const ResourceId lhsId = lhs.attrRef->id ? lhs.attrRef->id.value() : ResourceId(0);
+ const ResourceId rhsId = rhs.attrRef->id ? rhs.attrRef->id.value() : ResourceId(0);
+ if (lhsId < rhsId) {
+ return true;
+ } else if (lhsId > rhsId) {
+ return false;
+ } else {
+ return lhs.attrRef->name.value() < rhs.attrRef->name.value();
+ }
+}
+
void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outClassDef,
AnnotationProcessor* processor,
const StringPiece16& packageNameToGenerate,
const std::u16string& entryName,
const Styleable* styleable) {
+ const std::string className = transform(entryName);
+
// This must be sorted by resource ID.
- std::vector<std::pair<ResourceId, ResourceNameRef>> sortedAttributes;
+ std::vector<StyleableAttr> sortedAttributes;
sortedAttributes.reserve(styleable->entries.size());
for (const auto& attr : styleable->entries) {
// If we are not encoding final attributes, the styleable entry may have no ID
// if we are building a static library.
assert((!mOptions.useFinal || attr.id) && "no ID set for Styleable entry");
assert(attr.name && "no name set for Styleable entry");
- sortedAttributes.emplace_back(attr.id ? attr.id.value() : ResourceId(0), attr.name.value());
- }
- std::sort(sortedAttributes.begin(), sortedAttributes.end());
- auto accessorFunc = [](const std::pair<ResourceId, ResourceNameRef>& a) -> ResourceId {
- return a.first;
+ sortedAttributes.emplace_back(StyleableAttr{
+ &attr, transformNestedAttr(attr.name.value(), className, packageNameToGenerate) });
+ }
+ std::sort(sortedAttributes.begin(), sortedAttributes.end(), lessStyleableAttr);
+
+ const size_t attrCount = sortedAttributes.size();
+
+ if (attrCount > 0) {
+ // Build the comment string for the Styleable. It includes details about the
+ // child attributes.
+ std::stringstream styleableComment;
+ styleableComment << "Attributes that can be used with a " << className << ".\n";
+ styleableComment << "<table>\n"
+ "<colgroup align=\"left\" />\n"
+ "<colgroup align=\"left\">\n"
+ "<tr><th>Attribute</th><th>Description</th></tr>\n";
+ for (const auto& entry : sortedAttributes) {
+ const ResourceName& attrName = entry.attrRef->name.value();
+ styleableComment << "<tr><td><code>{@link #" << entry.fieldName << " "
+ << attrName.package << ":" << attrName.entry
+ << "}</code></td><td></td></tr>\n";
+ }
+ styleableComment << "</table>\n";
+ for (const auto& entry : sortedAttributes) {
+ styleableComment << "@see #" << entry.fieldName << "\n";
+ }
+ processor->appendComment(styleableComment.str());
+ }
+
+ auto accessorFunc = [](const StyleableAttr& a) -> ResourceId {
+ return a.attrRef->id ? a.attrRef->id.value() : ResourceId(0);
};
// First we emit the array containing the IDs of each attribute.
- outClassDef->addArrayMember(transform(entryName), processor,
+ outClassDef->addArrayMember(className, processor,
sortedAttributes.begin(),
sortedAttributes.end(),
accessorFunc);
// Now we emit the indices into the array.
- size_t attrCount = sortedAttributes.size();
for (size_t i = 0; i < attrCount; i++) {
- std::stringstream name;
- name << transform(entryName);
+ const ResourceName& attrName = sortedAttributes[i].attrRef->name.value();
- // We may reference IDs from other packages, so prefix the entry name with
- // the package.
- const ResourceNameRef& itemName = sortedAttributes[i].second;
- if (!itemName.package.empty() && packageNameToGenerate != itemName.package) {
- name << "_" << transform(itemName.package);
+ AnnotationProcessor attrProcessor;
+ std::stringstream doclavaComments;
+ doclavaComments << "@attr name ";
+ if (!attrName.package.empty()) {
+ doclavaComments << attrName.package << ":";
}
- name << "_" << transform(itemName.entry);
-
- outClassDef->addIntMember(name.str(), nullptr, i);
+ doclavaComments << attrName.entry;
+ attrProcessor.appendComment(doclavaComments.str());
+ outClassDef->addIntMember(sortedAttributes[i].fieldName, &attrProcessor, i);
}
}
@@ -223,8 +291,10 @@
continue;
}
- ResourceId id(package->id.value(), type->id.value(), entry->id.value());
- assert(id.isValid());
+ ResourceId id;
+ if (package->id && type->id && entry->id) {
+ id = ResourceId(package->id.value(), type->id.value(), entry->id.value());
+ }
std::u16string unmangledPackage;
std::u16string unmangledName = entry->name;
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index e9e7881..63d38a8 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -227,7 +227,32 @@
}
TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) {
+ Attribute attr(false);
+ attr.setComment(StringPiece16(u"This is an attribute"));
+ Styleable styleable;
+ styleable.entries.push_back(Reference(test::parseNameOrDie(u"@android:attr/one")));
+ styleable.setComment(StringPiece16(u"This is a styleable"));
+
+ std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
+ .setPackageId(u"android", 0x01)
+ .addValue(u"@android:attr/one", util::make_unique<Attribute>(attr))
+ .addValue(u"@android:styleable/Container",
+ std::unique_ptr<Styleable>(styleable.clone(nullptr)))
+ .build();
+
+ JavaClassGeneratorOptions options;
+ options.useFinal = false;
+ JavaClassGenerator generator(table.get(), options);
+
+ std::stringstream out;
+ ASSERT_TRUE(generator.generate(u"android", &out));
+ std::string actual = out.str();
+
+ EXPECT_NE(std::string::npos, actual.find("@attr name android:one"));
+ EXPECT_NE(std::string::npos, actual.find("@attr description"));
+ EXPECT_NE(std::string::npos, actual.find(util::utf16ToUtf8(attr.getComment())));
+ EXPECT_NE(std::string::npos, actual.find(util::utf16ToUtf8(styleable.getComment())));
}
} // namespace aapt
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index d83f6def..5003d96 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -62,7 +62,9 @@
std::set<std::u16string> extraJavaPackages;
Maybe<std::string> generateProguardRulesPath;
bool noAutoVersion = false;
+ bool noVersionVectors = false;
bool staticLib = false;
+ bool noStaticLibPackages = false;
bool generateNonFinalIds = false;
bool outputToDirectory = false;
bool autoAddOverlay = false;
@@ -74,37 +76,58 @@
TableSplitterOptions tableSplitterOptions;
};
-struct LinkContext : public IAaptContext {
- StdErrDiagnostics mDiagnostics;
- std::unique_ptr<NameMangler> mNameMangler;
- std::u16string mCompilationPackage;
- uint8_t mPackageId;
- std::unique_ptr<ISymbolTable> mSymbols;
- bool mVerbose = false;
+class LinkContext : public IAaptContext {
+public:
+ LinkContext() : mNameMangler({}) {
+ }
IDiagnostics* getDiagnostics() override {
return &mDiagnostics;
}
NameMangler* getNameMangler() override {
- return mNameMangler.get();
+ return &mNameMangler;
}
- StringPiece16 getCompilationPackage() override {
+ void setNameManglerPolicy(const NameManglerPolicy& policy) {
+ mNameMangler = NameMangler(policy);
+ }
+
+ const std::u16string& getCompilationPackage() override {
return mCompilationPackage;
}
+ void setCompilationPackage(const StringPiece16& packageName) {
+ mCompilationPackage = packageName.toString();
+ }
+
uint8_t getPackageId() override {
return mPackageId;
}
- ISymbolTable* getExternalSymbols() override {
- return mSymbols.get();
+ void setPackageId(uint8_t id) {
+ mPackageId = id;
+ }
+
+ SymbolTable* getExternalSymbols() override {
+ return &mSymbols;
}
bool verbose() override {
return mVerbose;
}
+
+ void setVerbose(bool val) {
+ mVerbose = val;
+ }
+
+private:
+ StdErrDiagnostics mDiagnostics;
+ NameMangler mNameMangler;
+ std::u16string mCompilationPackage;
+ uint8_t mPackageId = 0x0;
+ SymbolTable mSymbols;
+ bool mVerbose = false;
};
static bool copyFileToArchive(io::IFile* file, const std::string& outPath,
@@ -117,11 +140,19 @@
return false;
}
- CompiledFileInputStream inputStream(data->data(), data->size());
- if (!inputStream.CompiledFile()) {
- context->getDiagnostics()->error(DiagMessage(file->getSource())
- << "invalid compiled file header");
- return false;
+ const uint8_t* buffer = reinterpret_cast<const uint8_t*>(data->data());
+ size_t bufferSize = data->size();
+
+ // If the file ends with .flat, we must strip off the CompiledFileHeader from it.
+ if (util::stringEndsWith<char>(file->getSource().path, ".flat")) {
+ CompiledFileInputStream inputStream(data->data(), data->size());
+ if (!inputStream.CompiledFile()) {
+ context->getDiagnostics()->error(DiagMessage(file->getSource())
+ << "invalid compiled file header");
+ return false;
+ }
+ buffer = reinterpret_cast<const uint8_t*>(inputStream.data());
+ bufferSize = inputStream.size();
}
if (context->verbose()) {
@@ -129,8 +160,7 @@
}
if (writer->startEntry(outPath, compressionFlags)) {
- if (writer->writeEntry(reinterpret_cast<const uint8_t*>(inputStream.data()),
- inputStream.size())) {
+ if (writer->writeEntry(buffer, bufferSize)) {
if (writer->finishEntry()) {
return true;
}
@@ -156,7 +186,7 @@
DiagMessage msg;
msg << "writing " << path << " to archive";
if (maxSdkLevel) {
- msg << " maxSdkLevel=" << maxSdkLevel.value();
+ msg << " maxSdkLevel=" << maxSdkLevel.value() << " keepRawValues=" << keepRawValues;
}
context->getDiagnostics()->note(msg);
}
@@ -248,6 +278,7 @@
struct ResourceFileFlattenerOptions {
bool noAutoVersion = false;
+ bool noVersionVectors = false;
bool keepRawValues = false;
bool doNotCompressAnything = false;
std::vector<std::string> extensionsToNotCompress;
@@ -267,14 +298,13 @@
io::IFile* fileToCopy;
std::unique_ptr<xml::XmlResource> xmlToFlatten;
std::string dstPath;
+ bool skipVersion = false;
};
uint32_t getCompressionFlags(const StringPiece& str);
- std::unique_ptr<xml::XmlResource> linkAndVersionXmlFile(const ResourceEntry* entry,
- const ResourceFile& fileDesc,
- io::IFile* file,
- ResourceTable* table);
+ bool linkAndVersionXmlFile(const ResourceEntry* entry, const ResourceFile& fileDesc,
+ io::IFile* file, ResourceTable* table, FileOperation* outFileOp);
ResourceFileFlattenerOptions mOptions;
IAaptContext* mContext;
@@ -294,11 +324,11 @@
return ArchiveEntry::kCompress;
}
-std::unique_ptr<xml::XmlResource> ResourceFileFlattener::linkAndVersionXmlFile(
- const ResourceEntry* entry,
- const ResourceFile& fileDesc,
- io::IFile* file,
- ResourceTable* table) {
+bool ResourceFileFlattener::linkAndVersionXmlFile(const ResourceEntry* entry,
+ const ResourceFile& fileDesc,
+ io::IFile* file,
+ ResourceTable* table,
+ FileOperation* outFileOp) {
const StringPiece srcPath = file->getSource().path;
if (mContext->verbose()) {
mContext->getDiagnostics()->note(DiagMessage() << "linking " << srcPath);
@@ -307,51 +337,67 @@
std::unique_ptr<io::IData> data = file->openAsData();
if (!data) {
mContext->getDiagnostics()->error(DiagMessage(file->getSource()) << "failed to open file");
- return {};
+ return false;
}
- std::unique_ptr<xml::XmlResource> xmlRes;
if (util::stringEndsWith<char>(srcPath, ".flat")) {
- xmlRes = loadBinaryXmlSkipFileExport(file->getSource(), data->data(), data->size(),
- mContext->getDiagnostics());
+ outFileOp->xmlToFlatten = loadBinaryXmlSkipFileExport(file->getSource(),
+ data->data(), data->size(),
+ mContext->getDiagnostics());
} else {
- xmlRes = xml::inflate(data->data(), data->size(), mContext->getDiagnostics(),
- file->getSource());
+ outFileOp->xmlToFlatten = xml::inflate(data->data(), data->size(),
+ mContext->getDiagnostics(),
+ file->getSource());
}
- if (!xmlRes) {
- return {};
+ if (!outFileOp->xmlToFlatten) {
+ return false;
}
// Copy the the file description header.
- xmlRes->file = fileDesc;
+ outFileOp->xmlToFlatten->file = fileDesc;
XmlReferenceLinker xmlLinker;
- if (!xmlLinker.consume(mContext, xmlRes.get())) {
- return {};
+ if (!xmlLinker.consume(mContext, outFileOp->xmlToFlatten.get())) {
+ return false;
}
- if (!proguard::collectProguardRules(xmlRes->file.source, xmlRes.get(), mKeepSet)) {
- return {};
+ if (!proguard::collectProguardRules(outFileOp->xmlToFlatten->file.source,
+ outFileOp->xmlToFlatten.get(), mKeepSet)) {
+ return false;
}
if (!mOptions.noAutoVersion) {
+ if (mOptions.noVersionVectors) {
+ // Skip this if it is a vector or animated-vector.
+ xml::Element* el = xml::findRootElement(outFileOp->xmlToFlatten.get());
+ if (el && el->namespaceUri.empty()) {
+ if (el->name == u"vector" || el->name == u"animated-vector") {
+ // We are NOT going to version this file.
+ outFileOp->skipVersion = true;
+ return true;
+ }
+ }
+ }
+
// Find the first SDK level used that is higher than this defined config and
// not superseded by a lower or equal SDK level resource.
for (int sdkLevel : xmlLinker.getSdkLevels()) {
- if (sdkLevel > xmlRes->file.config.sdkVersion) {
- if (!shouldGenerateVersionedResource(entry, xmlRes->file.config, sdkLevel)) {
+ if (sdkLevel > outFileOp->xmlToFlatten->file.config.sdkVersion) {
+ if (!shouldGenerateVersionedResource(entry, outFileOp->xmlToFlatten->file.config,
+ sdkLevel)) {
// If we shouldn't generate a versioned resource, stop checking.
break;
}
- ResourceFile versionedFileDesc = xmlRes->file;
- versionedFileDesc.config.sdkVersion = sdkLevel;
+ ResourceFile versionedFileDesc = outFileOp->xmlToFlatten->file;
+ versionedFileDesc.config.sdkVersion = (uint16_t) sdkLevel;
if (mContext->verbose()) {
mContext->getDiagnostics()->note(DiagMessage(versionedFileDesc.source)
<< "auto-versioning resource from config '"
- << xmlRes->file.config << "' -> '"
+ << outFileOp->xmlToFlatten->file.config
+ << "' -> '"
<< versionedFileDesc.config << "'");
}
@@ -365,13 +411,13 @@
file,
mContext->getDiagnostics());
if (!added) {
- return {};
+ return false;
}
break;
}
}
}
- return xmlRes;
+ return true;
}
/**
@@ -415,9 +461,7 @@
fileDesc.config = configValue->config;
fileDesc.name = ResourceName(pkg->name, type->type, entry->name);
fileDesc.source = fileRef->getSource();
- fileOp.xmlToFlatten = linkAndVersionXmlFile(entry.get(), fileDesc,
- file, table);
- if (!fileOp.xmlToFlatten) {
+ if (!linkAndVersionXmlFile(entry.get(), fileDesc, file, table, &fileOp)) {
error = true;
continue;
}
@@ -447,7 +491,7 @@
if (fileOp.xmlToFlatten) {
Maybe<size_t> maxSdkLevel;
- if (!mOptions.noAutoVersion) {
+ if (!mOptions.noAutoVersion && !fileOp.skipVersion) {
maxSdkLevel = std::max<size_t>(config.sdkVersion, 1u);
}
@@ -474,39 +518,61 @@
class LinkCommand {
public:
LinkCommand(LinkContext* context, const LinkOptions& options) :
- mOptions(options), mContext(context), mFinalTable(), mFileCollection(nullptr) {
- std::unique_ptr<io::FileCollection> fileCollection =
- util::make_unique<io::FileCollection>();
-
- // Get a pointer to the FileCollection for convenience, but it will be owned by the vector.
- mFileCollection = fileCollection.get();
-
- // Move it to the collection.
- mCollections.push_back(std::move(fileCollection));
+ mOptions(options), mContext(context), mFinalTable(),
+ mFileCollection(util::make_unique<io::FileCollection>()) {
}
/**
* Creates a SymbolTable that loads symbols from the various APKs and caches the
* results for faster lookup.
*/
- std::unique_ptr<ISymbolTable> createSymbolTableFromIncludePaths() {
- AssetManagerSymbolTableBuilder builder;
+ bool loadSymbolsFromIncludePaths() {
+ std::unique_ptr<AssetManagerSymbolSource> assetSource =
+ util::make_unique<AssetManagerSymbolSource>();
for (const std::string& path : mOptions.includePaths) {
if (mContext->verbose()) {
mContext->getDiagnostics()->note(DiagMessage(path) << "loading include path");
}
- std::unique_ptr<android::AssetManager> assetManager =
- util::make_unique<android::AssetManager>();
- int32_t cookie = 0;
- if (!assetManager->addAssetPath(android::String8(path.data(), path.size()), &cookie)) {
+ // First try to load the file as a static lib.
+ std::string errorStr;
+ std::unique_ptr<ResourceTable> staticInclude = loadStaticLibrary(path, &errorStr);
+ if (staticInclude) {
+ if (!mOptions.staticLib) {
+ // Can't include static libraries when not building a static library.
+ mContext->getDiagnostics()->error(
+ DiagMessage(path) << "can't include static library when building app");
+ return false;
+ }
+
+ // If we are using --no-static-lib-packages, we need to rename the package of this
+ // table to our compilation package.
+ if (mOptions.noStaticLibPackages) {
+ if (ResourceTablePackage* pkg = staticInclude->findPackageById(0x7f)) {
+ pkg->name = mContext->getCompilationPackage();
+ }
+ }
+
+ mContext->getExternalSymbols()->appendSource(
+ util::make_unique<ResourceTableSymbolSource>(staticInclude.get()));
+
+ mStaticTableIncludes.push_back(std::move(staticInclude));
+
+ } else if (!errorStr.empty()) {
+ // We had an error with reading, so fail.
+ mContext->getDiagnostics()->error(DiagMessage(path) << errorStr);
+ return false;
+ }
+
+ if (!assetSource->addAssetPath(path)) {
mContext->getDiagnostics()->error(
DiagMessage(path) << "failed to load include path");
- return {};
+ return false;
}
- builder.add(std::move(assetManager));
}
- return builder.build();
+
+ mContext->getExternalSymbols()->appendSource(std::move(assetSource));
+ return true;
}
Maybe<AppInfo> extractAppInfoFromManifest(xml::XmlResource* xmlRes) {
@@ -571,6 +637,35 @@
return !error;
}
+ /**
+ * Returns true if no IDs have been set, false otherwise.
+ */
+ bool verifyNoIdsSet() {
+ for (const auto& package : mFinalTable.packages) {
+ for (const auto& type : package->types) {
+ if (type->id) {
+ mContext->getDiagnostics()->error(DiagMessage() << "type " << type->type
+ << " has ID " << std::hex
+ << (int) type->id.value()
+ << std::dec << " assigned");
+ return false;
+ }
+
+ for (const auto& entry : type->entries) {
+ if (entry->id) {
+ ResourceNameRef resName(package->name, type->type, entry->name);
+ mContext->getDiagnostics()->error(DiagMessage() << "entry " << resName
+ << " has ID " << std::hex
+ << (int) entry->id.value()
+ << std::dec << " assigned");
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
std::unique_ptr<IArchiveWriter> makeArchiveWriter() {
if (mOptions.outputToDirectory) {
return createDirectoryArchiveWriter(mContext->getDiagnostics(), mOptions.outputPath);
@@ -599,6 +694,32 @@
return false;
}
+ bool flattenTableToPb(ResourceTable* table, IArchiveWriter* writer) {
+ // Create the file/zip entry.
+ if (!writer->startEntry("resources.arsc.flat", 0)) {
+ mContext->getDiagnostics()->error(DiagMessage() << "failed to open");
+ return false;
+ }
+
+ std::unique_ptr<pb::ResourceTable> pbTable = serializeTableToPb(table);
+
+ // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream
+ // interface.
+ {
+ google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer);
+
+ if (!pbTable->SerializeToZeroCopyStream(&adaptor)) {
+ mContext->getDiagnostics()->error(DiagMessage() << "failed to write");
+ return false;
+ }
+ }
+
+ if (!writer->finishEntry()) {
+ mContext->getDiagnostics()->error(DiagMessage() << "failed to finish entry");
+ return false;
+ }
+ return true;
+ }
bool writeJavaFile(ResourceTable* table, const StringPiece16& packageNameToGenerate,
const StringPiece16& outPackage, JavaClassGeneratorOptions javaOptions) {
@@ -674,18 +795,91 @@
return true;
}
- bool mergeStaticLibrary(const std::string& input) {
- // TODO(adamlesinski): Load resources from a static library APK and merge the table into
- // TableMerger.
- mContext->getDiagnostics()->warn(DiagMessage()
- << "linking static libraries not supported yet: "
- << input);
+ std::unique_ptr<ResourceTable> loadStaticLibrary(const std::string& input,
+ std::string* outError) {
+ std::unique_ptr<io::ZipFileCollection> collection = io::ZipFileCollection::create(
+ input, outError);
+ if (!collection) {
+ return {};
+ }
+ return loadTablePbFromCollection(collection.get());
+ }
+
+ std::unique_ptr<ResourceTable> loadTablePbFromCollection(io::IFileCollection* collection) {
+ io::IFile* file = collection->findFile("resources.arsc.flat");
+ if (!file) {
+ return {};
+ }
+
+ std::unique_ptr<io::IData> data = file->openAsData();
+ return loadTableFromPb(file->getSource(), data->data(), data->size(),
+ mContext->getDiagnostics());
+ }
+
+ bool mergeStaticLibrary(const std::string& input, bool override) {
+ if (mContext->verbose()) {
+ mContext->getDiagnostics()->note(DiagMessage() << "merging static library " << input);
+ }
+
+ std::string errorStr;
+ std::unique_ptr<io::ZipFileCollection> collection =
+ io::ZipFileCollection::create(input, &errorStr);
+ if (!collection) {
+ mContext->getDiagnostics()->error(DiagMessage(input) << errorStr);
+ return false;
+ }
+
+ std::unique_ptr<ResourceTable> table = loadTablePbFromCollection(collection.get());
+ if (!table) {
+ mContext->getDiagnostics()->error(DiagMessage(input) << "invalid static library");
+ return false;
+ }
+
+ ResourceTablePackage* pkg = table->findPackageById(0x7f);
+ if (!pkg) {
+ mContext->getDiagnostics()->error(DiagMessage(input)
+ << "static library has no package");
+ return false;
+ }
+
+ bool result;
+ if (mOptions.noStaticLibPackages) {
+ // Merge all resources as if they were in the compilation package. This is the old
+ // behaviour of aapt.
+
+ // Add the package to the set of --extra-packages so we emit an R.java for each
+ // library package.
+ if (!pkg->name.empty()) {
+ mOptions.extraJavaPackages.insert(pkg->name);
+ }
+
+ pkg->name = u"";
+ if (override) {
+ result = mTableMerger->mergeOverlay(Source(input), table.get(), collection.get());
+ } else {
+ result = mTableMerger->merge(Source(input), table.get(), collection.get());
+ }
+
+ } else {
+ // This is the proper way to merge libraries, where the package name is preserved
+ // and resource names are mangled.
+ result = mTableMerger->mergeAndMangle(Source(input), pkg->name, table.get(),
+ collection.get());
+ }
+
+ if (!result) {
+ return false;
+ }
+
+ // Make sure to move the collection into the set of IFileCollections.
+ mCollections.push_back(std::move(collection));
return true;
}
bool mergeResourceTable(io::IFile* file, bool override) {
if (mContext->verbose()) {
- mContext->getDiagnostics()->note(DiagMessage() << "linking " << file->getSource());
+ mContext->getDiagnostics()->note(DiagMessage() << "merging resource table "
+ << file->getSource());
}
std::unique_ptr<io::IData> data = file->openAsData();
@@ -711,13 +905,14 @@
return result;
}
- bool mergeCompiledFile(io::IFile* file, std::unique_ptr<ResourceFile> fileDesc, bool overlay) {
+ bool mergeCompiledFile(io::IFile* file, ResourceFile* fileDesc, bool override) {
if (mContext->verbose()) {
- mContext->getDiagnostics()->note(DiagMessage() << "adding " << file->getSource());
+ mContext->getDiagnostics()->note(DiagMessage() << "merging compiled file "
+ << file->getSource());
}
bool result = false;
- if (overlay) {
+ if (override) {
result = mTableMerger->mergeFileOverlay(*fileDesc, file);
} else {
result = mTableMerger->mergeFile(*fileDesc, file);
@@ -730,7 +925,7 @@
// Add the exports of this file to the table.
for (SourcedResourceName& exportedSymbol : fileDesc->exportedSymbols) {
if (exportedSymbol.name.package.empty()) {
- exportedSymbol.name.package = mContext->getCompilationPackage().toString();
+ exportedSymbol.name.package = mContext->getCompilationPackage();
}
ResourceNameRef resName = exportedSymbol.name;
@@ -743,11 +938,9 @@
std::unique_ptr<Id> id = util::make_unique<Id>();
id->setSource(fileDesc->source.withLine(exportedSymbol.line));
- bool result = mFinalTable.addResourceAllowMangled(resName,
- ConfigDescription::defaultConfig(),
- std::string(),
- std::move(id),
- mContext->getDiagnostics());
+ bool result = mFinalTable.addResourceAllowMangled(
+ resName, ConfigDescription::defaultConfig(), std::string(), std::move(id),
+ mContext->getDiagnostics());
if (!result) {
return false;
}
@@ -756,12 +949,21 @@
}
/**
- * Creates an io::IFileCollection from the ZIP archive and processes the files within.
+ * Takes a path to load as a ZIP file and merges the files within into the master ResourceTable.
+ * If override is true, conflicting resources are allowed to override each other, in order of
+ * last seen.
+ *
+ * An io::IFileCollection is created from the ZIP file and added to the set of
+ * io::IFileCollections that are open.
*/
bool mergeArchive(const std::string& input, bool override) {
+ if (mContext->verbose()) {
+ mContext->getDiagnostics()->note(DiagMessage() << "merging archive " << input);
+ }
+
std::string errorStr;
- std::unique_ptr<io::ZipFileCollection> collection = io::ZipFileCollection::create(
- input, &errorStr);
+ std::unique_ptr<io::ZipFileCollection> collection =
+ io::ZipFileCollection::create(input, &errorStr);
if (!collection) {
mContext->getDiagnostics()->error(DiagMessage(input) << errorStr);
return false;
@@ -769,7 +971,7 @@
bool error = false;
for (auto iter = collection->iterator(); iter->hasNext(); ) {
- if (!processFile(iter->next(), override)) {
+ if (!mergeFile(iter->next(), override)) {
error = true;
}
}
@@ -779,22 +981,45 @@
return !error;
}
- bool processFile(const std::string& path, bool override) {
+ /**
+ * Takes a path to load and merge into the master ResourceTable. If override is true,
+ * conflicting resources are allowed to override each other, in order of last seen.
+ *
+ * If the file path ends with .flata, .jar, .jack, or .zip the file is treated as ZIP archive
+ * and the files within are merged individually.
+ *
+ * Otherwise the files is processed on its own.
+ */
+ bool mergePath(const std::string& path, bool override) {
if (util::stringEndsWith<char>(path, ".flata") ||
util::stringEndsWith<char>(path, ".jar") ||
util::stringEndsWith<char>(path, ".jack") ||
util::stringEndsWith<char>(path, ".zip")) {
return mergeArchive(path, override);
+ } else if (util::stringEndsWith<char>(path, ".apk")) {
+ return mergeStaticLibrary(path, override);
}
io::IFile* file = mFileCollection->insertFile(path);
- return processFile(file, override);
+ return mergeFile(file, override);
}
- bool processFile(io::IFile* file, bool override) {
+ /**
+ * Takes a file to load and merge into the master ResourceTable. If override is true,
+ * conflicting resources are allowed to override each other, in order of last seen.
+ *
+ * If the file ends with .arsc.flat, then it is loaded as a ResourceTable and merged into the
+ * master ResourceTable. If the file ends with .flat, then it is treated like a compiled file
+ * and the header data is read and merged into the final ResourceTable.
+ *
+ * All other file types are ignored. This is because these files could be coming from a zip,
+ * where we could have other files like classes.dex.
+ */
+ bool mergeFile(io::IFile* file, bool override) {
const Source& src = file->getSource();
if (util::stringEndsWith<char>(src.path, ".arsc.flat")) {
return mergeResourceTable(file, override);
+
} else if (util::stringEndsWith<char>(src.path, ".flat")){
// Try opening the file and looking for an Export header.
std::unique_ptr<io::IData> data = file->openAsData();
@@ -806,9 +1031,8 @@
std::unique_ptr<ResourceFile> resourceFile = loadFileExportHeader(
src, data->data(), data->size(), mContext->getDiagnostics());
if (resourceFile) {
- return mergeCompiledFile(file, std::move(resourceFile), override);
+ return mergeCompiledFile(file, resourceFile.get(), override);
}
-
return false;
}
@@ -826,32 +1050,30 @@
}
if (Maybe<AppInfo> maybeAppInfo = extractAppInfoFromManifest(manifestXml.get())) {
- mContext->mCompilationPackage = maybeAppInfo.value().package;
+ mContext->setCompilationPackage(maybeAppInfo.value().package);
} else {
mContext->getDiagnostics()->error(DiagMessage(mOptions.manifestPath)
<< "no package specified in <manifest> tag");
return 1;
}
- if (!util::isJavaPackageName(mContext->mCompilationPackage)) {
+ if (!util::isJavaPackageName(mContext->getCompilationPackage())) {
mContext->getDiagnostics()->error(DiagMessage(mOptions.manifestPath)
<< "invalid package name '"
- << mContext->mCompilationPackage
+ << mContext->getCompilationPackage()
<< "'");
return 1;
}
- mContext->mNameMangler = util::make_unique<NameMangler>(
- NameManglerPolicy{ mContext->mCompilationPackage });
+ mContext->setNameManglerPolicy(NameManglerPolicy{ mContext->getCompilationPackage() });
- if (mContext->mCompilationPackage == u"android") {
- mContext->mPackageId = 0x01;
+ if (mContext->getCompilationPackage() == u"android") {
+ mContext->setPackageId(0x01);
} else {
- mContext->mPackageId = 0x7f;
+ mContext->setPackageId(0x7f);
}
- mContext->mSymbols = createSymbolTableFromIncludePaths();
- if (!mContext->mSymbols) {
+ if (!loadSymbolsFromIncludePaths()) {
return 1;
}
@@ -861,20 +1083,21 @@
if (mContext->verbose()) {
mContext->getDiagnostics()->note(
- DiagMessage() << "linking package '" << mContext->mCompilationPackage << "' "
- << "with package ID " << std::hex << (int) mContext->mPackageId);
+ DiagMessage() << "linking package '" << mContext->getCompilationPackage()
+ << "' with package ID " << std::hex
+ << (int) mContext->getPackageId());
}
for (const std::string& input : inputFiles) {
- if (!processFile(input, false)) {
+ if (!mergePath(input, false)) {
mContext->getDiagnostics()->error(DiagMessage() << "failed parsing input");
return 1;
}
}
for (const std::string& input : mOptions.overlayFiles) {
- if (!processFile(input, true)) {
+ if (!mergePath(input, true)) {
mContext->getDiagnostics()->error(DiagMessage() << "failed parsing overlays");
return 1;
}
@@ -893,20 +1116,28 @@
}
}
- {
+ if (!mOptions.staticLib) {
+ // Assign IDs if we are building a regular app.
IdAssigner idAssigner;
if (!idAssigner.consume(mContext, &mFinalTable)) {
mContext->getDiagnostics()->error(DiagMessage() << "failed assigning IDs");
return 1;
}
+ } else {
+ // Static libs are merged with other apps, and ID collisions are bad, so verify that
+ // no IDs have been set.
+ if (!verifyNoIdsSet()) {
+ return 1;
+ }
}
- mContext->mNameMangler = util::make_unique<NameMangler>(NameManglerPolicy{
- mContext->mCompilationPackage, mTableMerger->getMergedPackages() });
- mContext->mSymbols = JoinedSymbolTableBuilder()
- .addSymbolTable(util::make_unique<SymbolTableWrapper>(&mFinalTable))
- .addSymbolTable(std::move(mContext->mSymbols))
- .build();
+ // Add the names to mangle based on our source merge earlier.
+ mContext->setNameManglerPolicy(NameManglerPolicy{
+ mContext->getCompilationPackage(), mTableMerger->getMergedPackages() });
+
+ // Add our table to the symbol table.
+ mContext->getExternalSymbols()->prependSource(
+ util::make_unique<ResourceTableSymbolSource>(&mFinalTable));
{
ReferenceLinker linker;
@@ -915,20 +1146,32 @@
return 1;
}
- ProductFilter productFilter(mOptions.products);
- if (!productFilter.consume(mContext, &mFinalTable)) {
- mContext->getDiagnostics()->error(DiagMessage() << "failed stripping products");
- return 1;
- }
+ if (mOptions.staticLib) {
+ if (!mOptions.products.empty()) {
+ mContext->getDiagnostics()->warn(
+ DiagMessage() << "can't select products when building static library");
+ }
- // TODO(adamlesinski): Actually pass in split constraints and handle splits at the file
- // level.
- TableSplitter tableSplitter({}, mOptions.tableSplitterOptions);
- if (!tableSplitter.verifySplitConstraints(mContext)) {
- return 1;
- }
+ if (mOptions.tableSplitterOptions.configFilter != nullptr ||
+ mOptions.tableSplitterOptions.preferredDensity) {
+ mContext->getDiagnostics()->warn(
+ DiagMessage() << "can't strip resources when building static library");
+ }
+ } else {
+ ProductFilter productFilter(mOptions.products);
+ if (!productFilter.consume(mContext, &mFinalTable)) {
+ mContext->getDiagnostics()->error(DiagMessage() << "failed stripping products");
+ return 1;
+ }
- tableSplitter.splitTable(&mFinalTable);
+ // TODO(adamlesinski): Actually pass in split constraints and handle splits at the file
+ // level.
+ TableSplitter tableSplitter({}, mOptions.tableSplitterOptions);
+ if (!tableSplitter.verifySplitConstraints(mContext)) {
+ return 1;
+ }
+ tableSplitter.splitTable(&mFinalTable);
+ }
}
proguard::KeepSet proguardKeepSet;
@@ -949,7 +1192,7 @@
// AndroidManifest.xml has no resource name, but the CallSite is built from the name
// (aka, which package the AndroidManifest.xml is coming from).
// So we give it a package name so it can see local resources.
- manifestXml->file.name.package = mContext->getCompilationPackage().toString();
+ manifestXml->file.name.package = mContext->getCompilationPackage();
XmlReferenceLinker manifestLinker;
if (manifestLinker.consume(mContext, manifestXml.get())) {
@@ -986,6 +1229,7 @@
fileFlattenerOptions.doNotCompressAnything = mOptions.doNotCompressAnything;
fileFlattenerOptions.extensionsToNotCompress = mOptions.extensionsToNotCompress;
fileFlattenerOptions.noAutoVersion = mOptions.noAutoVersion;
+ fileFlattenerOptions.noVersionVectors = mOptions.noVersionVectors;
ResourceFileFlattener fileFlattener(fileFlattenerOptions, mContext, &proguardKeepSet);
if (!fileFlattener.flatten(&mFinalTable, archiveWriter.get())) {
@@ -1001,9 +1245,18 @@
}
}
- if (!flattenTable(&mFinalTable, archiveWriter.get())) {
- mContext->getDiagnostics()->error(DiagMessage() << "failed to write resources.arsc");
- return 1;
+ if (mOptions.staticLib) {
+ if (!flattenTableToPb(&mFinalTable, archiveWriter.get())) {
+ mContext->getDiagnostics()->error(DiagMessage()
+ << "failed to write resources.arsc.flat");
+ return 1;
+ }
+ } else {
+ if (!flattenTable(&mFinalTable, archiveWriter.get())) {
+ mContext->getDiagnostics()->error(DiagMessage()
+ << "failed to write resources.arsc");
+ return 1;
+ }
}
if (mOptions.generateJavaClassPath) {
@@ -1065,14 +1318,17 @@
LinkContext* mContext;
ResourceTable mFinalTable;
- ResourceTable mLocalFileTable;
std::unique_ptr<TableMerger> mTableMerger;
// A pointer to the FileCollection representing the filesystem (not archives).
- io::FileCollection* mFileCollection;
+ std::unique_ptr<io::FileCollection> mFileCollection;
// A vector of IFileCollections. This is mainly here to keep ownership of the collections.
std::vector<std::unique_ptr<io::IFileCollection>> mCollections;
+
+ // A vector of ResourceTables. This is here to retain ownership, so that the SymbolTable
+ // can use these.
+ std::vector<std::unique_ptr<ResourceTable>> mStaticTableIncludes;
};
int link(const std::vector<StringPiece>& args) {
@@ -1089,6 +1345,7 @@
Maybe<std::string> productList;
bool legacyXFlag = false;
bool requireLocalization = false;
+ bool verbose = false;
Flags flags = Flags()
.requiredFlag("-o", "Output path", &options.outputPath)
.requiredFlag("--manifest", "Path to the Android manifest to build",
@@ -1104,6 +1361,10 @@
.optionalSwitch("--no-auto-version",
"Disables automatic style and layout SDK versioning",
&options.noAutoVersion)
+ .optionalSwitch("--no-version-vectors",
+ "Disables automatic versioning of vector drawables. Use this only\n"
+ "when building with vector drawable support library",
+ &options.noVersionVectors)
.optionalSwitch("-x", "Legacy flag that specifies to use the package identifier 0x01",
&legacyXFlag)
.optionalSwitch("-z", "Require localization of strings marked 'suggested'",
@@ -1127,6 +1388,9 @@
.optionalFlag("--version-name", "Version name to inject into the AndroidManifest.xml "
"if none is present", &versionName)
.optionalSwitch("--static-lib", "Generate a static Android library", &options.staticLib)
+ .optionalSwitch("--no-static-lib-packages",
+ "Merge all library resources under the app's package",
+ &options.noStaticLibPackages)
.optionalSwitch("--non-final-ids", "Generates R.java without the final modifier.\n"
"This is implied when --static-lib is specified.",
&options.generateNonFinalIds)
@@ -1148,12 +1412,16 @@
&renameInstrumentationTargetPackage)
.optionalFlagList("-0", "File extensions not to compress",
&options.extensionsToNotCompress)
- .optionalSwitch("-v", "Enables verbose logging", &context.mVerbose);
+ .optionalSwitch("-v", "Enables verbose logging", &verbose);
if (!flags.parse("aapt2 link", args, &std::cerr)) {
return 1;
}
+ if (verbose) {
+ context.setVerbose(verbose);
+ }
+
if (privateSymbolsPackage) {
options.privateSymbols = util::utf8ToUtf16(privateSymbolsPackage.value());
}
@@ -1252,6 +1520,12 @@
options.tableSplitterOptions.preferredDensity = preferredDensityConfig.density;
}
+ // Turn off auto versioning for static-libs.
+ if (options.staticLib) {
+ options.noAutoVersion = true;
+ options.noVersionVectors = true;
+ }
+
LinkCommand cmd(&context, options);
return cmd.run(flags.getArgs());
}
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index f40fbfb..18c47df 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -30,7 +30,7 @@
.setCompilationPackage(u"android")
.setPackageId(0x01)
.setNameManglerPolicy(NameManglerPolicy{ u"android" })
- .setSymbolTable(test::StaticSymbolTableBuilder()
+ .addSymbolSource(test::StaticSymbolSourceBuilder()
.addSymbol(u"@android:attr/package", ResourceId(0x01010000),
test::AttributeBuilder()
.setTypeMask(android::ResTable_map::TYPE_STRING)
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index ef3fe4f..66eb0df 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -14,9 +14,8 @@
* limitations under the License.
*/
-#include "ReferenceLinker.h"
-
#include "Diagnostics.h"
+#include "ReferenceLinker.h"
#include "ResourceTable.h"
#include "ResourceUtils.h"
#include "ResourceValues.h"
@@ -43,45 +42,10 @@
* NOTE: All of the entries in the ResourceTable must be assigned IDs.
*/
class ReferenceLinkerVisitor : public ValueVisitor {
-private:
- IAaptContext* mContext;
- ISymbolTable* mSymbols;
- xml::IPackageDeclStack* mPackageDecls;
- StringPool* mStringPool;
- CallSite* mCallSite;
- bool mError = false;
-
- /**
- * Transform a RawString value into a more specific, appropriate value, based on the
- * Attribute. If a non RawString value is passed in, this is an identity transform.
- */
- std::unique_ptr<Item> parseValueWithAttribute(std::unique_ptr<Item> value,
- const Attribute* attr) {
- if (RawString* rawString = valueCast<RawString>(value.get())) {
- std::unique_ptr<Item> transformed =
- ResourceUtils::parseItemForAttribute(*rawString->value, attr);
-
- // If we could not parse as any specific type, try a basic STRING.
- if (!transformed && (attr->typeMask & android::ResTable_map::TYPE_STRING)) {
- util::StringBuilder stringBuilder;
- stringBuilder.append(*rawString->value);
- if (stringBuilder) {
- transformed = util::make_unique<String>(
- mStringPool->makeRef(stringBuilder.str()));
- }
- }
-
- if (transformed) {
- return transformed;
- }
- };
- return value;
- }
-
public:
using ValueVisitor::visit;
- ReferenceLinkerVisitor(IAaptContext* context, ISymbolTable* symbols, StringPool* stringPool,
+ ReferenceLinkerVisitor(IAaptContext* context, SymbolTable* symbols, StringPool* stringPool,
xml::IPackageDeclStack* decl,CallSite* callSite) :
mContext(context), mSymbols(symbols), mPackageDecls(decl), mStringPool(stringPool),
mCallSite(callSite) {
@@ -114,10 +78,11 @@
&transformedReference);
// Find the attribute in the symbol table and check if it is visible from this callsite.
- const ISymbolTable::Symbol* symbol = ReferenceLinker::resolveAttributeCheckVisibility(
+ const SymbolTable::Symbol* symbol = ReferenceLinker::resolveAttributeCheckVisibility(
transformedReference, mContext->getNameMangler(), mSymbols, mCallSite, &errStr);
if (symbol) {
// Assign our style key the correct ID.
+ // The ID may not exist.
entry.key.id = symbol->id;
// Try to convert the value to a more specific, typed value based on the
@@ -156,6 +121,41 @@
bool hasError() {
return mError;
}
+
+private:
+ IAaptContext* mContext;
+ SymbolTable* mSymbols;
+ xml::IPackageDeclStack* mPackageDecls;
+ StringPool* mStringPool;
+ CallSite* mCallSite;
+ bool mError = false;
+
+ /**
+ * Transform a RawString value into a more specific, appropriate value, based on the
+ * Attribute. If a non RawString value is passed in, this is an identity transform.
+ */
+ std::unique_ptr<Item> parseValueWithAttribute(std::unique_ptr<Item> value,
+ const Attribute* attr) {
+ if (RawString* rawString = valueCast<RawString>(value.get())) {
+ std::unique_ptr<Item> transformed =
+ ResourceUtils::parseItemForAttribute(*rawString->value, attr);
+
+ // If we could not parse as any specific type, try a basic STRING.
+ if (!transformed && (attr->typeMask & android::ResTable_map::TYPE_STRING)) {
+ util::StringBuilder stringBuilder;
+ stringBuilder.append(*rawString->value);
+ if (stringBuilder) {
+ transformed = util::make_unique<String>(
+ mStringPool->makeRef(stringBuilder.str()));
+ }
+ }
+
+ if (transformed) {
+ return transformed;
+ }
+ };
+ return value;
+ }
};
} // namespace
@@ -164,13 +164,13 @@
* The symbol is visible if it is public, or if the reference to it is requesting private access
* or if the callsite comes from the same package.
*/
-bool ReferenceLinker::isSymbolVisible(const ISymbolTable::Symbol& symbol, const Reference& ref,
+bool ReferenceLinker::isSymbolVisible(const SymbolTable::Symbol& symbol, const Reference& ref,
const CallSite& callSite) {
if (!symbol.isPublic && !ref.privateReference) {
if (ref.name) {
return callSite.resource.package == ref.name.value().package;
- } else if (ref.id) {
- return ref.id.value().packageId() == symbol.id.packageId();
+ } else if (ref.id && symbol.id) {
+ return ref.id.value().packageId() == symbol.id.value().packageId();
} else {
return false;
}
@@ -178,9 +178,9 @@
return true;
}
-const ISymbolTable::Symbol* ReferenceLinker::resolveSymbol(const Reference& reference,
- NameMangler* mangler,
- ISymbolTable* symbols) {
+const SymbolTable::Symbol* ReferenceLinker::resolveSymbol(const Reference& reference,
+ NameMangler* mangler,
+ SymbolTable* symbols) {
if (reference.name) {
Maybe<ResourceName> mangled = mangler->mangleName(reference.name.value());
return symbols->findByName(mangled ? mangled.value() : reference.name.value());
@@ -191,10 +191,10 @@
}
}
-const ISymbolTable::Symbol* ReferenceLinker::resolveSymbolCheckVisibility(
- const Reference& reference, NameMangler* nameMangler, ISymbolTable* symbols,
+const SymbolTable::Symbol* ReferenceLinker::resolveSymbolCheckVisibility(
+ const Reference& reference, NameMangler* nameMangler, SymbolTable* symbols,
CallSite* callSite, std::string* outError) {
- const ISymbolTable::Symbol* symbol = resolveSymbol(reference, nameMangler, symbols);
+ const SymbolTable::Symbol* symbol = resolveSymbol(reference, nameMangler, symbols);
if (!symbol) {
if (outError) *outError = "not found";
return nullptr;
@@ -207,12 +207,12 @@
return symbol;
}
-const ISymbolTable::Symbol* ReferenceLinker::resolveAttributeCheckVisibility(
- const Reference& reference, NameMangler* nameMangler, ISymbolTable* symbols,
+const SymbolTable::Symbol* ReferenceLinker::resolveAttributeCheckVisibility(
+ const Reference& reference, NameMangler* nameMangler, SymbolTable* symbols,
CallSite* callSite, std::string* outError) {
- const ISymbolTable::Symbol* symbol = resolveSymbolCheckVisibility(reference, nameMangler,
- symbols, callSite,
- outError);
+ const SymbolTable::Symbol* symbol = resolveSymbolCheckVisibility(reference, nameMangler,
+ symbols, callSite,
+ outError);
if (!symbol) {
return nullptr;
}
@@ -226,10 +226,10 @@
Maybe<xml::AaptAttribute> ReferenceLinker::compileXmlAttribute(const Reference& reference,
NameMangler* nameMangler,
- ISymbolTable* symbols,
+ SymbolTable* symbols,
CallSite* callSite,
std::string* outError) {
- const ISymbolTable::Symbol* symbol = resolveSymbol(reference, nameMangler, symbols);
+ const SymbolTable::Symbol* symbol = resolveSymbol(reference, nameMangler, symbols);
if (!symbol) {
return {};
}
@@ -256,7 +256,7 @@
}
bool ReferenceLinker::linkReference(Reference* reference, IAaptContext* context,
- ISymbolTable* symbols, xml::IPackageDeclStack* decls,
+ SymbolTable* symbols, xml::IPackageDeclStack* decls,
CallSite* callSite) {
assert(reference);
assert(reference->name || reference->id);
@@ -266,9 +266,12 @@
&transformedReference);
std::string errStr;
- const ISymbolTable::Symbol* s = resolveSymbolCheckVisibility(
+ const SymbolTable::Symbol* s = resolveSymbolCheckVisibility(
transformedReference, context->getNameMangler(), symbols, callSite, &errStr);
if (s) {
+ // The ID may not exist. This is fine because of the possibility of building against
+ // libraries without assigned IDs.
+ // Ex: Linking against own resources when building a static library.
reference->id = s->id;
return true;
}
diff --git a/tools/aapt2/link/ReferenceLinker.h b/tools/aapt2/link/ReferenceLinker.h
index a0eb00c..7993aaf 100644
--- a/tools/aapt2/link/ReferenceLinker.h
+++ b/tools/aapt2/link/ReferenceLinker.h
@@ -38,36 +38,36 @@
/**
* Returns true if the symbol is visible by the reference and from the callsite.
*/
- static bool isSymbolVisible(const ISymbolTable::Symbol& symbol, const Reference& ref,
+ static bool isSymbolVisible(const SymbolTable::Symbol& symbol, const Reference& ref,
const CallSite& callSite);
/**
* Performs name mangling and looks up the resource in the symbol table. Returns nullptr
* if the symbol was not found.
*/
- static const ISymbolTable::Symbol* resolveSymbol(const Reference& reference,
- NameMangler* mangler, ISymbolTable* symbols);
+ static const SymbolTable::Symbol* resolveSymbol(const Reference& reference,
+ NameMangler* mangler, SymbolTable* symbols);
/**
* Performs name mangling and looks up the resource in the symbol table. If the symbol is
* not visible by the reference at the callsite, nullptr is returned. outError holds
* the error message.
*/
- static const ISymbolTable::Symbol* resolveSymbolCheckVisibility(const Reference& reference,
- NameMangler* nameMangler,
- ISymbolTable* symbols,
- CallSite* callSite,
- std::string* outError);
+ static const SymbolTable::Symbol* resolveSymbolCheckVisibility(const Reference& reference,
+ NameMangler* nameMangler,
+ SymbolTable* symbols,
+ CallSite* callSite,
+ std::string* outError);
/**
* Same as resolveSymbolCheckVisibility(), but also makes sure the symbol is an attribute.
* That is, the return value will have a non-null value for ISymbolTable::Symbol::attribute.
*/
- static const ISymbolTable::Symbol* resolveAttributeCheckVisibility(const Reference& reference,
- NameMangler* nameMangler,
- ISymbolTable* symbols,
- CallSite* callSite,
- std::string* outError);
+ static const SymbolTable::Symbol* resolveAttributeCheckVisibility(const Reference& reference,
+ NameMangler* nameMangler,
+ SymbolTable* symbols,
+ CallSite* callSite,
+ std::string* outError);
/**
* Resolves the attribute reference and returns an xml::AaptAttribute if successful.
@@ -75,7 +75,7 @@
*/
static Maybe<xml::AaptAttribute> compileXmlAttribute(const Reference& reference,
NameMangler* nameMangler,
- ISymbolTable* symbols,
+ SymbolTable* symbols,
CallSite* callSite,
std::string* outError);
@@ -92,7 +92,7 @@
* to the reference at the callsite, the reference is updated with an ID.
* Returns false on failure, and an error message is logged to the IDiagnostics in the context.
*/
- static bool linkReference(Reference* reference, IAaptContext* context, ISymbolTable* symbols,
+ static bool linkReference(Reference* reference, IAaptContext* context, SymbolTable* symbols,
xml::IPackageDeclStack* decls, CallSite* callSite);
/**
diff --git a/tools/aapt2/link/ReferenceLinker_test.cpp b/tools/aapt2/link/ReferenceLinker_test.cpp
index 8d324fe..76b2309 100644
--- a/tools/aapt2/link/ReferenceLinker_test.cpp
+++ b/tools/aapt2/link/ReferenceLinker_test.cpp
@@ -15,12 +15,9 @@
*/
#include "link/ReferenceLinker.h"
-#include "process/SymbolTable.h"
+#include "test/Test.h"
-#include "test/Builders.h"
-#include "test/Context.h"
-
-#include <gtest/gtest.h>
+using android::ResTable_map;
namespace aapt {
@@ -41,12 +38,10 @@
.setCompilationPackage(u"com.app.test")
.setPackageId(0x7f)
.setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
- .setSymbolTable(JoinedSymbolTableBuilder()
- .addSymbolTable(util::make_unique<SymbolTableWrapper>(table.get()))
- .addSymbolTable(test::StaticSymbolTableBuilder()
- .addPublicSymbol(u"@android:string/ok", ResourceId(0x01040034))
- .build())
- .build())
+ .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+ .addSymbolSource(test::StaticSymbolSourceBuilder()
+ .addPublicSymbol(u"@android:string/ok", ResourceId(0x01040034))
+ .build())
.build();
ReferenceLinker linker;
@@ -91,19 +86,20 @@
.setCompilationPackage(u"com.app.test")
.setPackageId(0x7f)
.setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
- .setSymbolTable(test::StaticSymbolTableBuilder()
- .addPublicSymbol(u"@android:style/Theme.Material", ResourceId(0x01060000))
- .addPublicSymbol(u"@android:attr/foo", ResourceId(0x01010001),
- test::AttributeBuilder()
- .setTypeMask(android::ResTable_map::TYPE_COLOR)
- .build())
- .addPublicSymbol(u"@android:attr/bar", ResourceId(0x01010002),
- test::AttributeBuilder()
- .setTypeMask(android::ResTable_map::TYPE_FLAGS)
- .addItem(u"one", 0x01)
- .addItem(u"two", 0x02)
- .build())
- .build())
+ .addSymbolSource(test::StaticSymbolSourceBuilder()
+ .addPublicSymbol(u"@android:style/Theme.Material",
+ ResourceId(0x01060000))
+ .addPublicSymbol(u"@android:attr/foo", ResourceId(0x01010001),
+ test::AttributeBuilder()
+ .setTypeMask(ResTable_map::TYPE_COLOR)
+ .build())
+ .addPublicSymbol(u"@android:attr/bar", ResourceId(0x01010002),
+ test::AttributeBuilder()
+ .setTypeMask(ResTable_map::TYPE_FLAGS)
+ .addItem(u"one", 0x01)
+ .addItem(u"two", 0x02)
+ .build())
+ .build())
.build();
ReferenceLinker linker;
@@ -131,11 +127,13 @@
.setCompilationPackage(u"com.app.test")
.setPackageId(0x7f)
.setNameManglerPolicy(NameManglerPolicy{ u"com.app.test", { u"com.android.support" } })
- .setSymbolTable(test::StaticSymbolTableBuilder()
- .addPublicSymbol(u"@com.app.test:attr/com.android.support$foo",
- ResourceId(0x7f010000), test::AttributeBuilder()
- .setTypeMask(android::ResTable_map::TYPE_COLOR).build())
- .build())
+ .addSymbolSource(test::StaticSymbolSourceBuilder()
+ .addPublicSymbol(u"@com.app.test:attr/com.android.support$foo",
+ ResourceId(0x7f010000),
+ test::AttributeBuilder()
+ .setTypeMask(ResTable_map::TYPE_COLOR)
+ .build())
+ .build())
.build();
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
@@ -167,12 +165,10 @@
.setCompilationPackage(u"com.app.test")
.setPackageId(0x7f)
.setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
- .setSymbolTable(JoinedSymbolTableBuilder()
- .addSymbolTable(util::make_unique<SymbolTableWrapper>(table.get()))
- .addSymbolTable(test::StaticSymbolTableBuilder()
- .addSymbol(u"@android:string/hidden", ResourceId(0x01040034))
- .build())
- .build())
+ .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+ .addSymbolSource(test::StaticSymbolSourceBuilder()
+ .addSymbol(u"@android:string/hidden", ResourceId(0x01040034))
+ .build())
.build();
ReferenceLinker linker;
@@ -190,13 +186,12 @@
.setCompilationPackage(u"com.app.test")
.setPackageId(0x7f)
.setNameManglerPolicy(NameManglerPolicy{ u"com.app.test", { u"com.app.lib" } })
- .setSymbolTable(JoinedSymbolTableBuilder()
- .addSymbolTable(util::make_unique<SymbolTableWrapper>(table.get()))
- .addSymbolTable(test::StaticSymbolTableBuilder()
- .addSymbol(u"@com.app.test:string/com.app.lib$hidden",
- ResourceId(0x7f040034))
- .build())
- .build())
+ .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+ .addSymbolSource(test::StaticSymbolSourceBuilder()
+ .addSymbol(u"@com.app.test:string/com.app.lib$hidden",
+ ResourceId(0x7f040034))
+ .build())
+
.build();
ReferenceLinker linker;
@@ -215,15 +210,14 @@
.setCompilationPackage(u"com.app.test")
.setPackageId(0x7f)
.setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
- .setSymbolTable(JoinedSymbolTableBuilder()
- .addSymbolTable(util::make_unique<SymbolTableWrapper>(table.get()))
- .addSymbolTable(test::StaticSymbolTableBuilder()
- .addSymbol(u"@android:attr/hidden", ResourceId(0x01010001),
- test::AttributeBuilder()
- .setTypeMask(android::ResTable_map::TYPE_COLOR)
- .build())
- .build())
- .build())
+ .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+ .addSymbolSource(test::StaticSymbolSourceBuilder()
+ .addSymbol(u"@android:attr/hidden", ResourceId(0x01010001),
+ test::AttributeBuilder()
+ .setTypeMask(
+ android::ResTable_map::TYPE_COLOR)
+ .build())
+ .build())
.build();
ReferenceLinker linker;
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index 5f11745..7471e15 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -34,10 +34,21 @@
assert(mMasterPackage && "package name or ID already taken");
}
+bool TableMerger::merge(const Source& src, ResourceTable* table,
+ io::IFileCollection* collection) {
+ return mergeImpl(src, table, collection, false /* overlay */, true /* allow new */);
+}
+
+bool TableMerger::mergeOverlay(const Source& src, ResourceTable* table,
+ io::IFileCollection* collection) {
+ return mergeImpl(src, table, collection, true /* overlay */, mOptions.autoAddOverlay);
+}
+
/**
* This will merge packages with the same package name (or no package name).
*/
bool TableMerger::mergeImpl(const Source& src, ResourceTable* table,
+ io::IFileCollection* collection,
bool overlay, bool allowNew) {
const uint8_t desiredPackageId = mContext->getPackageId();
@@ -51,26 +62,36 @@
}
if (package->name.empty() || mContext->getCompilationPackage() == package->name) {
+ FileMergeCallback callback;
+ if (collection) {
+ callback = [&](const ResourceNameRef& name, const ConfigDescription& config,
+ FileReference* newFile, FileReference* oldFile) -> bool {
+ // The old file's path points inside the APK, so we can use it as is.
+ io::IFile* f = collection->findFile(util::utf16ToUtf8(*oldFile->path));
+ if (!f) {
+ mContext->getDiagnostics()->error(DiagMessage(src) << "file '"
+ << *oldFile->path
+ << "' not found");
+ return false;
+ }
+
+ newFile->file = f;
+ return true;
+ };
+ }
+
// Merge here. Once the entries are merged and mangled, any references to
// them are still valid. This is because un-mangled references are
// mangled, then looked up at resolution time.
// Also, when linking, we convert references with no package name to use
// the compilation package name.
error |= !doMerge(src, table, package.get(),
- false /* mangle */, overlay, allowNew, {});
+ false /* mangle */, overlay, allowNew, callback);
}
}
return !error;
}
-bool TableMerger::merge(const Source& src, ResourceTable* table) {
- return mergeImpl(src, table, false /* overlay */, true /* allow new */);
-}
-
-bool TableMerger::mergeOverlay(const Source& src, ResourceTable* table) {
- return mergeImpl(src, table, true /* overlay */, mOptions.autoAddOverlay);
-}
-
/**
* This will merge and mangle resources from a static library.
*/
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index b3c22dd..80c2a5e 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -65,13 +65,17 @@
/**
* Merges resources from the same or empty package. This is for local sources.
+ * An io::IFileCollection is optional and used to find the referenced Files and process them.
*/
- bool merge(const Source& src, ResourceTable* table);
+ bool merge(const Source& src, ResourceTable* table,
+ io::IFileCollection* collection = nullptr);
/**
* Merges resources from an overlay ResourceTable.
+ * An io::IFileCollection is optional and used to find the referenced Files and process them.
*/
- bool mergeOverlay(const Source& src, ResourceTable* table);
+ bool mergeOverlay(const Source& src, ResourceTable* table,
+ io::IFileCollection* collection = nullptr);
/**
* Merges resources from the given package, mangling the name. This is for static libraries.
@@ -104,7 +108,7 @@
bool mergeFileImpl(const ResourceFile& fileDesc, io::IFile* file, bool overlay);
- bool mergeImpl(const Source& src, ResourceTable* srcTable,
+ bool mergeImpl(const Source& src, ResourceTable* srcTable, io::IFileCollection* collection,
bool overlay, bool allowNew);
bool doMerge(const Source& src, ResourceTable* srcTable, ResourceTablePackage* srcPackage,
diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp
index a26d763..568bc74 100644
--- a/tools/aapt2/link/XmlReferenceLinker.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker.cpp
@@ -34,17 +34,10 @@
* as needed.
*/
class ReferenceVisitor : public ValueVisitor {
-private:
- IAaptContext* mContext;
- ISymbolTable* mSymbols;
- xml::IPackageDeclStack* mDecls;
- CallSite* mCallSite;
- bool mError;
-
public:
using ValueVisitor::visit;
- ReferenceVisitor(IAaptContext* context, ISymbolTable* symbols, xml::IPackageDeclStack* decls,
+ ReferenceVisitor(IAaptContext* context, SymbolTable* symbols, xml::IPackageDeclStack* decls,
CallSite* callSite) :
mContext(context), mSymbols(symbols), mDecls(decls), mCallSite(callSite),
mError(false) {
@@ -59,25 +52,23 @@
bool hasError() const {
return mError;
}
+
+private:
+ IAaptContext* mContext;
+ SymbolTable* mSymbols;
+ xml::IPackageDeclStack* mDecls;
+ CallSite* mCallSite;
+ bool mError;
};
/**
* Visits each xml Element and compiles the attributes within.
*/
class XmlVisitor : public xml::PackageAwareVisitor {
-private:
- IAaptContext* mContext;
- ISymbolTable* mSymbols;
- Source mSource;
- std::set<int>* mSdkLevelsFound;
- CallSite* mCallSite;
- ReferenceVisitor mReferenceVisitor;
- bool mError = false;
-
public:
using xml::PackageAwareVisitor::visit;
- XmlVisitor(IAaptContext* context, ISymbolTable* symbols, const Source& source,
+ XmlVisitor(IAaptContext* context, SymbolTable* symbols, const Source& source,
std::set<int>* sdkLevelsFound, CallSite* callSite) :
mContext(context), mSymbols(symbols), mSource(source), mSdkLevelsFound(sdkLevelsFound),
mCallSite(callSite), mReferenceVisitor(context, symbols, this, callSite) {
@@ -105,10 +96,13 @@
// Convert the string value into a compiled Value if this is a valid attribute.
if (attr.compiledAttribute) {
- // Record all SDK levels from which the attributes were defined.
- const int sdkLevel = findAttributeSdkLevel(attr.compiledAttribute.value().id);
- if (sdkLevel > 1) {
- mSdkLevelsFound->insert(sdkLevel);
+ if (attr.compiledAttribute.value().id) {
+ // Record all SDK levels from which the attributes were defined.
+ const size_t sdkLevel = findAttributeSdkLevel(
+ attr.compiledAttribute.value().id.value());
+ if (sdkLevel > 1) {
+ mSdkLevelsFound->insert(sdkLevel);
+ }
}
const Attribute* attribute = &attr.compiledAttribute.value().attribute;
@@ -124,6 +118,7 @@
<< *attribute);
mError = true;
}
+
} else {
mContext->getDiagnostics()->error(DiagMessage(source)
<< "attribute '" << package << ":"
@@ -150,6 +145,15 @@
bool hasError() {
return mError || mReferenceVisitor.hasError();
}
+
+private:
+ IAaptContext* mContext;
+ SymbolTable* mSymbols;
+ Source mSource;
+ std::set<int>* mSdkLevelsFound;
+ CallSite* mCallSite;
+ ReferenceVisitor mReferenceVisitor;
+ bool mError = false;
};
} // namespace
diff --git a/tools/aapt2/link/XmlReferenceLinker_test.cpp b/tools/aapt2/link/XmlReferenceLinker_test.cpp
index 3bfaf91..af9098b 100644
--- a/tools/aapt2/link/XmlReferenceLinker_test.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker_test.cpp
@@ -14,12 +14,9 @@
* limitations under the License.
*/
+#include <test/Context.h>
#include "link/Linkers.h"
-
-#include "test/Builders.h"
-#include "test/Context.h"
-
-#include <gtest/gtest.h>
+#include "test/Test.h"
namespace aapt {
@@ -30,7 +27,7 @@
.setCompilationPackage(u"com.app.test")
.setNameManglerPolicy(
NameManglerPolicy{ u"com.app.test", { u"com.android.support" } })
- .setSymbolTable(test::StaticSymbolTableBuilder()
+ .addSymbolSource(test::StaticSymbolSourceBuilder()
.addPublicSymbol(u"@android:attr/layout_width", ResourceId(0x01010000),
test::AttributeBuilder()
.setTypeMask(android::ResTable_map::TYPE_ENUM |
@@ -92,14 +89,16 @@
u"layout_width");
ASSERT_NE(xmlAttr, nullptr);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
- EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x01010000));
+ AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+ EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x01010000));
ASSERT_NE(xmlAttr->compiledValue, nullptr);
ASSERT_NE(valueCast<BinaryPrimitive>(xmlAttr->compiledValue.get()), nullptr);
xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res/android", u"background");
ASSERT_NE(xmlAttr, nullptr);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
- EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x01010001));
+ AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+ EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x01010001));
ASSERT_NE(xmlAttr->compiledValue, nullptr);
Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get());
ASSERT_NE(ref, nullptr);
@@ -163,7 +162,8 @@
u"http://schemas.android.com/apk/res/com.android.support", u"colorAccent");
ASSERT_NE(xmlAttr, nullptr);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
- EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x7f010001));
+ AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+ EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x7f010001));
ASSERT_NE(valueCast<BinaryPrimitive>(xmlAttr->compiledValue.get()), nullptr);
}
@@ -182,7 +182,8 @@
u"colorAccent");
ASSERT_NE(xmlAttr, nullptr);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
- EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x7f010000));
+ AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+ EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x7f010000));
Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get());
ASSERT_NE(ref, nullptr);
AAPT_ASSERT_TRUE(ref->name);
@@ -209,7 +210,8 @@
u"attr");
ASSERT_NE(xmlAttr, nullptr);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
- EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x01010002));
+ AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+ EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x01010002));
Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get());
ASSERT_NE(ref, nullptr);
AAPT_ASSERT_TRUE(ref->id);
@@ -223,7 +225,8 @@
xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res/com.app.test", u"attr");
ASSERT_NE(xmlAttr, nullptr);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
- EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x7f010002));
+ AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+ EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x7f010002));
ref = valueCast<Reference>(xmlAttr->compiledValue.get());
ASSERT_NE(ref, nullptr);
AAPT_ASSERT_TRUE(ref->id);
@@ -246,7 +249,8 @@
u"http://schemas.android.com/apk/res/com.app.test", u"attr");
ASSERT_NE(xmlAttr, nullptr);
AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
- EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x7f010002));
+ AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+ EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x7f010002));
Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get());
ASSERT_NE(ref, nullptr);
AAPT_ASSERT_TRUE(ref->id);
diff --git a/tools/aapt2/process/IResourceTableConsumer.h b/tools/aapt2/process/IResourceTableConsumer.h
index 3a88044..9affb83 100644
--- a/tools/aapt2/process/IResourceTableConsumer.h
+++ b/tools/aapt2/process/IResourceTableConsumer.h
@@ -30,14 +30,14 @@
namespace aapt {
class ResourceTable;
-struct ISymbolTable;
+class SymbolTable;
struct IAaptContext {
virtual ~IAaptContext() = default;
- virtual ISymbolTable* getExternalSymbols() = 0;
+ virtual SymbolTable* getExternalSymbols() = 0;
virtual IDiagnostics* getDiagnostics() = 0;
- virtual StringPiece16 getCompilationPackage() = 0;
+ virtual const std::u16string& getCompilationPackage() = 0;
virtual uint8_t getPackageId() = 0;
virtual NameMangler* getNameMangler() = 0;
virtual bool verbose() = 0;
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index b6030a2..a8f9bfe 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -25,11 +25,59 @@
namespace aapt {
-const ISymbolTable::Symbol* SymbolTableWrapper::findByName(const ResourceName& name) {
+void SymbolTable::appendSource(std::unique_ptr<ISymbolSource> source) {
+ mSources.push_back(std::move(source));
+
+ // We do not clear the cache, because sources earlier in the list take precedent.
+}
+
+void SymbolTable::prependSource(std::unique_ptr<ISymbolSource> source) {
+ mSources.insert(mSources.begin(), std::move(source));
+
+ // We must clear the cache in case we did a lookup before adding this resource.
+ mCache.clear();
+}
+
+const SymbolTable::Symbol* SymbolTable::findByName(const ResourceName& name) {
if (const std::shared_ptr<Symbol>& s = mCache.get(name)) {
return s.get();
}
+ // We did not find it in the cache, so look through the sources.
+ for (auto& symbolSource : mSources) {
+ std::unique_ptr<Symbol> symbol = symbolSource->findByName(name);
+ if (symbol) {
+ // Take ownership of the symbol into a shared_ptr. We do this because LruCache
+ // doesn't support unique_ptr.
+ std::shared_ptr<Symbol> sharedSymbol = std::shared_ptr<Symbol>(symbol.release());
+ mCache.put(name, sharedSymbol);
+ return sharedSymbol.get();
+ }
+ }
+ return nullptr;
+}
+
+const SymbolTable::Symbol* SymbolTable::findById(ResourceId id) {
+ if (const std::shared_ptr<Symbol>& s = mIdCache.get(id)) {
+ return s.get();
+ }
+
+ // We did not find it in the cache, so look through the sources.
+ for (auto& symbolSource : mSources) {
+ std::unique_ptr<Symbol> symbol = symbolSource->findById(id);
+ if (symbol) {
+ // Take ownership of the symbol into a shared_ptr. We do this because LruCache
+ // doesn't support unique_ptr.
+ std::shared_ptr<Symbol> sharedSymbol = std::shared_ptr<Symbol>(symbol.release());
+ mIdCache.put(id, sharedSymbol);
+ return sharedSymbol.get();
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<SymbolTable::Symbol> ResourceTableSymbolSource::findByName(
+ const ResourceName& name) {
Maybe<ResourceTable::SearchResult> result = mTable->findResource(name);
if (!result) {
if (name.type == ResourceType::kAttr) {
@@ -41,16 +89,13 @@
ResourceTable::SearchResult sr = result.value();
- // If no ID exists, we treat the symbol as missing. SymbolTables are used to
- // find symbols to link.
- if (!sr.package->id || !sr.type->id || !sr.entry->id) {
- return {};
- }
-
- std::shared_ptr<Symbol> symbol = std::make_shared<Symbol>();
- symbol->id = ResourceId(sr.package->id.value(), sr.type->id.value(), sr.entry->id.value());
+ std::unique_ptr<SymbolTable::Symbol> symbol = util::make_unique<SymbolTable::Symbol>();
symbol->isPublic = (sr.entry->symbolStatus.state == SymbolState::kPublic);
+ if (sr.package->id && sr.type->id && sr.entry->id) {
+ symbol->id = ResourceId(sr.package->id.value(), sr.type->id.value(), sr.entry->id.value());
+ }
+
if (name.type == ResourceType::kAttr || name.type == ResourceType::kAttrPrivate) {
const ConfigDescription kDefaultConfig;
ResourceConfigValue* configValue = sr.entry->findValue(kDefaultConfig);
@@ -63,18 +108,16 @@
}
}
}
-
- if (name.type == ResourceType::kAttrPrivate) {
- // Masquerade this entry as kAttr.
- mCache.put(ResourceName(name.package, ResourceType::kAttr, name.entry), symbol);
- } else {
- mCache.put(name, symbol);
- }
- return symbol.get();
+ return symbol;
}
-static std::shared_ptr<ISymbolTable::Symbol> lookupAttributeInTable(const android::ResTable& table,
- ResourceId id) {
+bool AssetManagerSymbolSource::addAssetPath(const StringPiece& path) {
+ int32_t cookie = 0;
+ return mAssets.addAssetPath(android::String8(path.data(), path.size()), &cookie);
+}
+
+static std::unique_ptr<SymbolTable::Symbol> lookupAttributeInTable(const android::ResTable& table,
+ ResourceId id) {
// Try as a bag.
const android::ResTable::bag_entry* entry;
ssize_t count = table.lockBag(id.id, &entry);
@@ -84,7 +127,7 @@
}
// We found a resource.
- std::shared_ptr<ISymbolTable::Symbol> s = std::make_shared<ISymbolTable::Symbol>();
+ std::unique_ptr<SymbolTable::Symbol> s = util::make_unique<SymbolTable::Symbol>();
s->id = id;
// Check to see if it is an attribute.
@@ -138,43 +181,36 @@
return s;
}
-const ISymbolTable::Symbol* AssetManagerSymbolTableBuilder::AssetManagerSymbolTable::findByName(
+std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::findByName(
const ResourceName& name) {
- if (const std::shared_ptr<Symbol>& s = mCache.get(name)) {
- return s.get();
+ const android::ResTable& table = mAssets.getResources(false);
+ StringPiece16 typeStr = toString(name.type);
+ uint32_t typeSpecFlags = 0;
+ ResourceId resId = table.identifierForName(name.entry.data(), name.entry.size(),
+ typeStr.data(), typeStr.size(),
+ name.package.data(), name.package.size(),
+ &typeSpecFlags);
+ if (!resId.isValid()) {
+ return {};
}
- for (const auto& asset : mAssets) {
- const android::ResTable& table = asset->getResources(false);
- StringPiece16 typeStr = toString(name.type);
- uint32_t typeSpecFlags = 0;
- ResourceId resId = table.identifierForName(name.entry.data(), name.entry.size(),
- typeStr.data(), typeStr.size(),
- name.package.data(), name.package.size(),
- &typeSpecFlags);
- if (!resId.isValid()) {
- continue;
- }
-
- std::shared_ptr<Symbol> s;
- if (name.type == ResourceType::kAttr) {
- s = lookupAttributeInTable(table, resId);
- } else {
- s = std::make_shared<Symbol>();
- s->id = resId;
- }
-
- if (s) {
- s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
- mCache.put(name, s);
- return s.get();
- }
+ std::unique_ptr<SymbolTable::Symbol> s;
+ if (name.type == ResourceType::kAttr) {
+ s = lookupAttributeInTable(table, resId);
+ } else {
+ s = util::make_unique<SymbolTable::Symbol>();
+ s->id = resId;
}
- return nullptr;
+
+ if (s) {
+ s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
+ return s;
+ }
+ return {};
}
static Maybe<ResourceName> getResourceName(const android::ResTable& table, ResourceId id) {
- android::ResTable::resource_name resName;
+ android::ResTable::resource_name resName = {};
if (!table.getResourceName(id.id, true, &resName)) {
return {};
}
@@ -211,55 +247,27 @@
return name;
}
-const ISymbolTable::Symbol* AssetManagerSymbolTableBuilder::AssetManagerSymbolTable::findById(
- ResourceId id) {
- if (const std::shared_ptr<Symbol>& s = mIdCache.get(id)) {
- return s.get();
+std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::findById(ResourceId id) {
+ const android::ResTable& table = mAssets.getResources(false);
+ Maybe<ResourceName> maybeName = getResourceName(table, id);
+ if (!maybeName) {
+ return {};
}
- for (const auto& asset : mAssets) {
- const android::ResTable& table = asset->getResources(false);
+ uint32_t typeSpecFlags = 0;
+ table.getResourceFlags(id.id, &typeSpecFlags);
- Maybe<ResourceName> maybeName = getResourceName(table, id);
- if (!maybeName) {
- continue;
- }
-
- uint32_t typeSpecFlags = 0;
- table.getResourceFlags(id.id, &typeSpecFlags);
-
- std::shared_ptr<Symbol> s;
- if (maybeName.value().type == ResourceType::kAttr) {
- s = lookupAttributeInTable(table, id);
- } else {
- s = std::make_shared<Symbol>();
- s->id = id;
- }
-
- if (s) {
- s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
- mIdCache.put(id, s);
- return s.get();
- }
+ std::unique_ptr<SymbolTable::Symbol> s;
+ if (maybeName.value().type == ResourceType::kAttr) {
+ s = lookupAttributeInTable(table, id);
+ } else {
+ s = util::make_unique<SymbolTable::Symbol>();
+ s->id = id;
}
- return nullptr;
-}
-const ISymbolTable::Symbol* JoinedSymbolTableBuilder::JoinedSymbolTable::findByName(
- const ResourceName& name) {
- for (auto& symbolTable : mSymbolTables) {
- if (const Symbol* s = symbolTable->findByName(name)) {
- return s;
- }
- }
- return {};
-}
-
-const ISymbolTable::Symbol* JoinedSymbolTableBuilder::JoinedSymbolTable::findById(ResourceId id) {
- for (auto& symbolTable : mSymbolTables) {
- if (const Symbol* s = symbolTable->findById(id)) {
- return s;
- }
+ if (s) {
+ s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
+ return s;
}
return {};
}
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index 22096ed..8ea1c75 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -25,37 +25,20 @@
#include <utils/JenkinsHash.h>
#include <utils/LruCache.h>
+#include <android-base/macros.h>
#include <androidfw/AssetManager.h>
#include <algorithm>
-#include <map>
#include <memory>
#include <vector>
namespace aapt {
-struct ISymbolTable {
- virtual ~ISymbolTable() = default;
-
- struct Symbol {
- ResourceId id;
- std::unique_ptr<Attribute> attribute;
- bool isPublic;
- };
-
- /**
- * Never hold on to the result between calls to findByName or findById. The results
- * are typically stored in a cache which may evict entries.
- */
- virtual const Symbol* findByName(const ResourceName& name) = 0;
- virtual const Symbol* findById(ResourceId id) = 0;
-};
-
inline android::hash_t hash_type(const ResourceName& name) {
std::hash<std::u16string> strHash;
android::hash_t hash = 0;
- hash = android::JenkinsHashMix(hash, strHash(name.package));
+ hash = android::JenkinsHashMix(hash, (uint32_t) strHash(name.package));
hash = android::JenkinsHashMix(hash, (uint32_t) name.type);
- hash = android::JenkinsHashMix(hash, strHash(name.entry));
+ hash = android::JenkinsHashMix(hash, (uint32_t) strHash(name.entry));
return hash;
}
@@ -63,88 +46,87 @@
return android::hash_type(id.id);
}
-/**
- * Presents a ResourceTable as an ISymbolTable, caching results.
- * Instances of this class must outlive the encompassed ResourceTable.
- * Since symbols are cached, the ResourceTable should not change during the
- * lifetime of this SymbolTableWrapper.
- *
- * If a resource in the ResourceTable does not have a ResourceID assigned to it,
- * it is ignored.
- *
- * Lookups by ID are ignored.
- */
-class SymbolTableWrapper : public ISymbolTable {
+class ISymbolSource;
+
+class SymbolTable {
+public:
+ struct Symbol {
+ Maybe<ResourceId> id;
+ std::unique_ptr<Attribute> attribute;
+ bool isPublic;
+ };
+
+ SymbolTable() : mCache(200), mIdCache(200) {
+ }
+
+ void appendSource(std::unique_ptr<ISymbolSource> source);
+ void prependSource(std::unique_ptr<ISymbolSource> source);
+
+ /**
+ * Never hold on to the result between calls to findByName or findById. The results
+ * are typically stored in a cache which may evict entries.
+ */
+ const Symbol* findByName(const ResourceName& name);
+ const Symbol* findById(ResourceId id);
+
private:
- ResourceTable* mTable;
+ std::vector<std::unique_ptr<ISymbolSource>> mSources;
// We use shared_ptr because unique_ptr is not supported and
// we need automatic deletion.
android::LruCache<ResourceName, std::shared_ptr<Symbol>> mCache;
+ android::LruCache<ResourceId, std::shared_ptr<Symbol>> mIdCache;
+ DISALLOW_COPY_AND_ASSIGN(SymbolTable);
+};
+
+/**
+ * An interface that a symbol source implements in order to surface symbol information
+ * to the symbol table.
+ */
+class ISymbolSource {
public:
- SymbolTableWrapper(ResourceTable* table) : mTable(table), mCache(200) {
+ virtual ~ISymbolSource() = default;
+
+ virtual std::unique_ptr<SymbolTable::Symbol> findByName(const ResourceName& name) = 0;
+ virtual std::unique_ptr<SymbolTable::Symbol> findById(ResourceId id) = 0;
+};
+
+/**
+ * Exposes the resources in a ResourceTable as symbols for SymbolTable.
+ * Instances of this class must outlive the encompassed ResourceTable.
+ * Lookups by ID are ignored.
+ */
+class ResourceTableSymbolSource : public ISymbolSource {
+public:
+ explicit ResourceTableSymbolSource(ResourceTable* table) : mTable(table) {
}
- const Symbol* findByName(const ResourceName& name) override;
+ std::unique_ptr<SymbolTable::Symbol> findByName(const ResourceName& name) override;
- // Unsupported, all queries to ResourceTable should be done by name.
- const Symbol* findById(ResourceId id) override {
+ std::unique_ptr<SymbolTable::Symbol> findById(ResourceId id) override {
return {};
}
+
+private:
+ ResourceTable* mTable;
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceTableSymbolSource);
};
-class AssetManagerSymbolTableBuilder {
-private:
- struct AssetManagerSymbolTable : public ISymbolTable {
- std::vector<std::unique_ptr<android::AssetManager>> mAssets;
-
- // We use shared_ptr because unique_ptr is not supported and
- // we need automatic deletion.
- android::LruCache<ResourceName, std::shared_ptr<Symbol>> mCache;
- android::LruCache<ResourceId, std::shared_ptr<Symbol>> mIdCache;
-
- AssetManagerSymbolTable() : mCache(200), mIdCache(200) {
- }
-
- const Symbol* findByName(const ResourceName& name) override;
- const Symbol* findById(ResourceId id) override;
- };
-
- std::unique_ptr<AssetManagerSymbolTable> mSymbolTable =
- util::make_unique<AssetManagerSymbolTable>();
-
+class AssetManagerSymbolSource : public ISymbolSource {
public:
- AssetManagerSymbolTableBuilder& add(std::unique_ptr<android::AssetManager> assetManager) {
- mSymbolTable->mAssets.push_back(std::move(assetManager));
- return *this;
- }
+ AssetManagerSymbolSource() = default;
- std::unique_ptr<ISymbolTable> build() {
- return std::move(mSymbolTable);
- }
-};
+ bool addAssetPath(const StringPiece& path);
-class JoinedSymbolTableBuilder {
+ std::unique_ptr<SymbolTable::Symbol> findByName(const ResourceName& name) override;
+ std::unique_ptr<SymbolTable::Symbol> findById(ResourceId id) override;
+
private:
- struct JoinedSymbolTable : public ISymbolTable {
- std::vector<std::unique_ptr<ISymbolTable>> mSymbolTables;
+ android::AssetManager mAssets;
- const Symbol* findByName(const ResourceName& name) override;
- const Symbol* findById(ResourceId id) override;
- };
-
- std::unique_ptr<JoinedSymbolTable> mSymbolTable = util::make_unique<JoinedSymbolTable>();
-
-public:
- JoinedSymbolTableBuilder& addSymbolTable(std::unique_ptr<ISymbolTable> table) {
- mSymbolTable->mSymbolTables.push_back(std::move(table));
- return *this;
- }
-
- std::unique_ptr<ISymbolTable> build() {
- return std::move(mSymbolTable);
- }
+ DISALLOW_COPY_AND_ASSIGN(AssetManagerSymbolSource);
};
} // namespace aapt
diff --git a/tools/aapt2/process/SymbolTable_test.cpp b/tools/aapt2/process/SymbolTable_test.cpp
index 1dc3b4f..34f31be 100644
--- a/tools/aapt2/process/SymbolTable_test.cpp
+++ b/tools/aapt2/process/SymbolTable_test.cpp
@@ -15,14 +15,11 @@
*/
#include "process/SymbolTable.h"
-#include "test/Builders.h"
-#include "test/Context.h"
-
-#include <gtest/gtest.h>
+#include "test/Test.h"
namespace aapt {
-TEST(SymbolTableWrapperTest, FindSymbolsWithIds) {
+TEST(ResourceTableSymbolSourceTest, FindSymbols) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
.addSimple(u"@android:id/foo", ResourceId(0x01020000))
.addSimple(u"@android:id/bar")
@@ -30,27 +27,27 @@
test::AttributeBuilder().build())
.build();
- SymbolTableWrapper symbolTable(table.get());
- EXPECT_NE(symbolTable.findByName(test::parseNameOrDie(u"@android:id/foo")), nullptr);
- EXPECT_EQ(symbolTable.findByName(test::parseNameOrDie(u"@android:id/bar")), nullptr);
+ ResourceTableSymbolSource symbolSource(table.get());
+ EXPECT_NE(nullptr, symbolSource.findByName(test::parseNameOrDie(u"@android:id/foo")));
+ EXPECT_NE(nullptr, symbolSource.findByName(test::parseNameOrDie(u"@android:id/bar")));
- const ISymbolTable::Symbol* s = symbolTable.findByName(
+ std::unique_ptr<SymbolTable::Symbol> s = symbolSource.findByName(
test::parseNameOrDie(u"@android:attr/foo"));
- ASSERT_NE(s, nullptr);
- EXPECT_NE(s->attribute, nullptr);
+ ASSERT_NE(nullptr, s);
+ EXPECT_NE(nullptr, s->attribute);
}
-TEST(SymbolTableWrapperTest, FindPrivateAttrSymbol) {
+TEST(ResourceTableSymbolSourceTest, FindPrivateAttrSymbol) {
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
.addValue(u"@android:^attr-private/foo", ResourceId(0x01010000),
test::AttributeBuilder().build())
.build();
- SymbolTableWrapper symbolTable(table.get());
- const ISymbolTable::Symbol* s = symbolTable.findByName(
+ ResourceTableSymbolSource symbolSource(table.get());
+ std::unique_ptr<SymbolTable::Symbol> s = symbolSource.findByName(
test::parseNameOrDie(u"@android:attr/foo"));
- ASSERT_NE(s, nullptr);
- EXPECT_NE(s->attribute, nullptr);
+ ASSERT_NE(nullptr, s);
+ EXPECT_NE(nullptr, s->attribute);
}
} // namespace aapt
diff --git a/tools/aapt2/proto/TableProtoDeserializer.cpp b/tools/aapt2/proto/TableProtoDeserializer.cpp
index 9856a00..86883f8 100644
--- a/tools/aapt2/proto/TableProtoDeserializer.cpp
+++ b/tools/aapt2/proto/TableProtoDeserializer.cpp
@@ -483,8 +483,13 @@
}
const size_t padding = 4 - (pbSize & 0x03);
- mData += sizeof(uint64_t) + pbSize + padding;
- mSize -= sizeof(uint64_t) + pbSize + padding;
+ const size_t offset = sizeof(uint64_t) + pbSize + padding;
+ if (offset > mSize) {
+ return nullptr;
+ }
+
+ mData += offset;
+ mSize -= offset;
mPbFile = std::move(pbFile);
}
return mPbFile.get();
diff --git a/tools/aapt2/proto/TableProtoSerializer.cpp b/tools/aapt2/proto/TableProtoSerializer.cpp
index b3d87d8..5d1b72b 100644
--- a/tools/aapt2/proto/TableProtoSerializer.cpp
+++ b/tools/aapt2/proto/TableProtoSerializer.cpp
@@ -178,10 +178,13 @@
void serializeReferenceToPb(const Reference& ref, pb::Reference* pbRef) {
if (ref.id) {
pbRef->set_id(ref.id.value().id);
- } else if (ref.name) {
+ }
+
+ if (ref.name) {
StringPool::Ref symbolRef = mSymbolPool->makeRef(ref.name.value().toString());
pbRef->set_symbol_idx(static_cast<uint32_t>(symbolRef.getIndex()));
}
+
pbRef->set_private_(ref.privateReference);
pbRef->set_type(serializeReferenceTypeToPb(ref.referenceType));
}
diff --git a/tools/aapt2/proto/TableProtoSerializer_test.cpp b/tools/aapt2/proto/TableProtoSerializer_test.cpp
index 70a33f7..dd995d8 100644
--- a/tools/aapt2/proto/TableProtoSerializer_test.cpp
+++ b/tools/aapt2/proto/TableProtoSerializer_test.cpp
@@ -62,6 +62,17 @@
test::buildPrimitive(android::Res_value::TYPE_INT_DEC, 321u),
context->getDiagnostics()));
+ // Make a reference with both resource name and resource ID.
+ // The reference should point to a resource outside of this table to test that both
+ // name and id get serialized.
+ Reference expectedRef;
+ expectedRef.name = test::parseNameOrDie(u"@android:layout/main");
+ expectedRef.id = ResourceId(0x01020000);
+ ASSERT_TRUE(table->addResource(test::parseNameOrDie(u"@com.app.a:layout/abc"),
+ ConfigDescription::defaultConfig(), std::string(),
+ util::make_unique<Reference>(expectedRef),
+ context->getDiagnostics()));
+
std::unique_ptr<pb::ResourceTable> pbTable = serializeTableToPb(table.get());
ASSERT_NE(nullptr, pbTable);
@@ -90,6 +101,13 @@
newTable.get(), u"@com.app.a:integer/one", test::parseConfigOrDie("land"), "tablet");
ASSERT_NE(nullptr, prim);
EXPECT_EQ(321u, prim->value.data);
+
+ Reference* actualRef = test::getValue<Reference>(newTable.get(), u"@com.app.a:layout/abc");
+ ASSERT_NE(nullptr, actualRef);
+ AAPT_ASSERT_TRUE(actualRef->name);
+ AAPT_ASSERT_TRUE(actualRef->id);
+ EXPECT_EQ(expectedRef.name.value(), actualRef->name.value());
+ EXPECT_EQ(expectedRef.id.value(), actualRef->id.value());
}
TEST(TableProtoSerializer, SerializeFileHeader) {
@@ -130,4 +148,27 @@
EXPECT_EQ(test::parseNameOrDie(u"@+id/unchecked"), file->exportedSymbols[0].name);
}
+TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) {
+ ResourceFile f;
+ std::unique_ptr<pb::CompiledFile> pbFile = serializeCompiledFileToPb(f);
+
+ const std::string expectedData = "1234";
+
+ std::string outputStr;
+ {
+ google::protobuf::io::StringOutputStream outStream(&outputStr);
+ CompiledFileOutputStream outFileStream(&outStream, pbFile.get());
+
+ ASSERT_TRUE(outFileStream.Write(expectedData.data(), expectedData.size()));
+ ASSERT_TRUE(outFileStream.Finish());
+ }
+
+ outputStr[0] = 0xff;
+
+ CompiledFileInputStream inFileStream(outputStr.data(), outputStr.size());
+ EXPECT_EQ(nullptr, inFileStream.CompiledFile());
+ EXPECT_EQ(nullptr, inFileStream.data());
+ EXPECT_EQ(0u, inFileStream.size());
+}
+
} // namespace aapt
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 834caf8..8c56ebc 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -246,7 +246,7 @@
inline std::unique_ptr<xml::XmlResource> buildXmlDomForPackageName(IAaptContext* context,
const StringPiece& str) {
std::unique_ptr<xml::XmlResource> doc = buildXmlDom(str);
- doc->file.name.package = context->getCompilationPackage().toString();
+ doc->file.name.package = context->getCompilationPackage();
return doc;
}
diff --git a/tools/aapt2/test/Context.h b/tools/aapt2/test/Context.h
index e540cd7..96752d3 100644
--- a/tools/aapt2/test/Context.h
+++ b/tools/aapt2/test/Context.h
@@ -31,33 +31,16 @@
namespace test {
class Context : public IAaptContext {
-private:
- friend class ContextBuilder;
-
- Context() = default;
-
- Maybe<std::u16string> mCompilationPackage;
- Maybe<uint8_t> mPackageId;
- std::unique_ptr<IDiagnostics> mDiagnostics = util::make_unique<StdErrDiagnostics>();
- std::unique_ptr<ISymbolTable> mSymbols;
- std::unique_ptr<NameMangler> mNameMangler;
-
public:
- ISymbolTable* getExternalSymbols() override {
- assert(mSymbols && "test symbols not set");
- return mSymbols.get();
- }
-
- void setSymbolTable(std::unique_ptr<ISymbolTable> symbols) {
- mSymbols = std::move(symbols);
+ SymbolTable* getExternalSymbols() override {
+ return &mSymbols;
}
IDiagnostics* getDiagnostics() override {
- assert(mDiagnostics && "test diagnostics not set");
- return mDiagnostics.get();
+ return &mDiagnostics;
}
- StringPiece16 getCompilationPackage() override {
+ const std::u16string& getCompilationPackage() override {
assert(mCompilationPackage && "package name not set");
return mCompilationPackage.value();
}
@@ -68,13 +51,24 @@
}
NameMangler* getNameMangler() override {
- assert(mNameMangler && "test name mangler not set");
- return mNameMangler.get();
+ return &mNameMangler;
}
bool verbose() override {
return false;
}
+
+private:
+ friend class ContextBuilder;
+
+ Context() : mNameMangler({}) {
+ }
+
+ Maybe<std::u16string> mCompilationPackage;
+ Maybe<uint8_t> mPackageId;
+ StdErrDiagnostics mDiagnostics;
+ SymbolTable mSymbols;
+ NameMangler mNameMangler;
};
class ContextBuilder {
@@ -92,18 +86,13 @@
return *this;
}
- ContextBuilder& setSymbolTable(std::unique_ptr<ISymbolTable> symbols) {
- mContext->mSymbols = std::move(symbols);
- return *this;
- }
-
- ContextBuilder& setDiagnostics(std::unique_ptr<IDiagnostics> diag) {
- mContext->mDiagnostics = std::move(diag);
- return *this;
- }
-
ContextBuilder& setNameManglerPolicy(NameManglerPolicy policy) {
- mContext->mNameMangler = util::make_unique<NameMangler>(policy);
+ mContext->mNameMangler = NameMangler(policy);
+ return *this;
+ }
+
+ ContextBuilder& addSymbolSource(std::unique_ptr<ISymbolSource> src) {
+ mContext->getExternalSymbols()->appendSource(std::move(src));
return *this;
}
@@ -112,57 +101,72 @@
}
};
-class StaticSymbolTableBuilder {
-private:
- struct SymbolTable : public ISymbolTable {
- std::list<std::unique_ptr<Symbol>> mSymbols;
- std::map<ResourceName, Symbol*> mNameMap;
- std::map<ResourceId, Symbol*> mIdMap;
+class StaticSymbolSourceBuilder {
+public:
+ StaticSymbolSourceBuilder& addPublicSymbol(const StringPiece16& name, ResourceId id,
+ std::unique_ptr<Attribute> attr = {}) {
+ std::unique_ptr<SymbolTable::Symbol> symbol = util::make_unique<SymbolTable::Symbol>(
+ id, std::move(attr), true);
+ mSymbolSource->mNameMap[parseNameOrDie(name)] = symbol.get();
+ mSymbolSource->mIdMap[id] = symbol.get();
+ mSymbolSource->mSymbols.push_back(std::move(symbol));
+ return *this;
+ }
- const Symbol* findByName(const ResourceName& name) override {
+ StaticSymbolSourceBuilder& addSymbol(const StringPiece16& name, ResourceId id,
+ std::unique_ptr<Attribute> attr = {}) {
+ std::unique_ptr<SymbolTable::Symbol> symbol = util::make_unique<SymbolTable::Symbol>(
+ id, std::move(attr), false);
+ mSymbolSource->mNameMap[parseNameOrDie(name)] = symbol.get();
+ mSymbolSource->mIdMap[id] = symbol.get();
+ mSymbolSource->mSymbols.push_back(std::move(symbol));
+ return *this;
+ }
+
+ std::unique_ptr<ISymbolSource> build() {
+ return std::move(mSymbolSource);
+ }
+
+private:
+ class StaticSymbolSource : public ISymbolSource {
+ public:
+ StaticSymbolSource() = default;
+
+ std::unique_ptr<SymbolTable::Symbol> findByName(const ResourceName& name) override {
auto iter = mNameMap.find(name);
if (iter != mNameMap.end()) {
- return iter->second;
+ return cloneSymbol(iter->second);
}
return nullptr;
}
- const Symbol* findById(ResourceId id) override {
+ std::unique_ptr<SymbolTable::Symbol> findById(ResourceId id) override {
auto iter = mIdMap.find(id);
if (iter != mIdMap.end()) {
- return iter->second;
+ return cloneSymbol(iter->second);
}
return nullptr;
}
+
+ std::list<std::unique_ptr<SymbolTable::Symbol>> mSymbols;
+ std::map<ResourceName, SymbolTable::Symbol*> mNameMap;
+ std::map<ResourceId, SymbolTable::Symbol*> mIdMap;
+
+ private:
+ std::unique_ptr<SymbolTable::Symbol> cloneSymbol(SymbolTable::Symbol* sym) {
+ std::unique_ptr<SymbolTable::Symbol> clone = util::make_unique<SymbolTable::Symbol>();
+ clone->id = sym->id;
+ if (sym->attribute) {
+ clone->attribute = std::unique_ptr<Attribute>(sym->attribute->clone(nullptr));
+ }
+ clone->isPublic = sym->isPublic;
+ return clone;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(StaticSymbolSource);
};
- std::unique_ptr<SymbolTable> mSymbolTable = util::make_unique<SymbolTable>();
-
-public:
- StaticSymbolTableBuilder& addPublicSymbol(const StringPiece16& name, ResourceId id,
- std::unique_ptr<Attribute> attr = {}) {
- std::unique_ptr<ISymbolTable::Symbol> symbol = util::make_unique<ISymbolTable::Symbol>(
- id, std::move(attr));
- symbol->isPublic = true;
- mSymbolTable->mNameMap[parseNameOrDie(name)] = symbol.get();
- mSymbolTable->mIdMap[id] = symbol.get();
- mSymbolTable->mSymbols.push_back(std::move(symbol));
- return *this;
- }
-
- StaticSymbolTableBuilder& addSymbol(const StringPiece16& name, ResourceId id,
- std::unique_ptr<Attribute> attr = {}) {
- std::unique_ptr<ISymbolTable::Symbol> symbol = util::make_unique<ISymbolTable::Symbol>(
- id, std::move(attr));
- mSymbolTable->mNameMap[parseNameOrDie(name)] = symbol.get();
- mSymbolTable->mIdMap[id] = symbol.get();
- mSymbolTable->mSymbols.push_back(std::move(symbol));
- return *this;
- }
-
- std::unique_ptr<ISymbolTable> build() {
- return std::move(mSymbolTable);
- }
+ std::unique_ptr<StaticSymbolSource> mSymbolSource = util::make_unique<StaticSymbolSource>();
};
} // namespace test
diff --git a/core/java/android/hardware/camera2/utils/LongParcelable.aidl b/tools/aapt2/test/Test.h
similarity index 63%
copy from core/java/android/hardware/camera2/utils/LongParcelable.aidl
copy to tools/aapt2/test/Test.h
index 98ad1b2..d4845cf 100644
--- a/core/java/android/hardware/camera2/utils/LongParcelable.aidl
+++ b/tools/aapt2/test/Test.h
@@ -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,19 @@
* limitations under the License.
*/
-package android.hardware.camera2.utils;
+#ifndef AAPT_TEST_TEST_H
+#define AAPT_TEST_TEST_H
-/** @hide */
-parcelable LongParcelable;
+#include "test/Builders.h"
+#include "test/Common.h"
+#include "test/Context.h"
+
+#include <gtest/gtest.h>
+
+namespace aapt {
+namespace test {
+
+} // namespace test
+} // namespace aapt
+
+#endif // AAPT_TEST_TEST_H
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index 033b0a4d..b374d20 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -68,7 +68,7 @@
};
struct AaptAttribute {
- ResourceId id;
+ Maybe<ResourceId> id;
aapt::Attribute attribute;
};
diff --git a/tools/layoutlib/.idea/libraries/junit.xml b/tools/layoutlib/.idea/libraries/junit.xml
new file mode 100644
index 0000000..c889f5f
--- /dev/null
+++ b/tools/layoutlib/.idea/libraries/junit.xml
@@ -0,0 +1,11 @@
+<component name="libraryTable">
+ <library name="junit">
+ <CLASSES>
+ <root url="jar://$PROJECT_DIR$/../../../../out/host/common/obj/JAVA_LIBRARIES/junit_intermediates/javalib.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="file://$PROJECT_DIR$/../../../../external/junit/src" />
+ </SOURCES>
+ </library>
+</component>
\ No newline at end of file
diff --git a/tools/layoutlib/.idea/runConfigurations/Create.xml b/tools/layoutlib/.idea/runConfigurations/Create.xml
index 58f057a..536a23f 100644
--- a/tools/layoutlib/.idea/runConfigurations/Create.xml
+++ b/tools/layoutlib/.idea/runConfigurations/Create.xml
@@ -2,8 +2,8 @@
<configuration default="false" name="Create" type="Application" factoryName="Application" singleton="true">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<option name="MAIN_CLASS_NAME" value="com.android.tools.layoutlib.create.Main" />
- <option name="VM_PARAMETERS" value="" />
- <option name="PROGRAM_PARAMETERS" value="out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar out/target/common/obj/JAVA_LIBRARIES/core-libart_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/icu4j-icudata-jarjar_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/icu4j-icutzdata-jarjar_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/javalib.jar" />
+ <option name="VM_PARAMETERS" value="-ea" />
+ <option name="PROGRAM_PARAMETERS" value="out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar out/target/common/obj/JAVA_LIBRARIES/core-libart_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar out/host/common/obj/JAVA_LIBRARIES/icu4j-icudata-host-jarjar_intermediates/classes-jarjar.jar out/host/common/obj/JAVA_LIBRARIES/icu4j-icutzdata-host-jarjar_intermediates/classes-jarjar.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/javalib.jar" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/../../../../" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" value="" />
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/bridge.iml b/tools/layoutlib/bridge/bridge.iml
index ccc10b3..57d08cb 100644
--- a/tools/layoutlib/bridge/bridge.iml
+++ b/tools/layoutlib/bridge/bridge.iml
@@ -84,6 +84,6 @@
</SOURCES>
</library>
</orderEntry>
- <orderEntry type="library" scope="TEST" name="JUnit4" level="application" />
+ <orderEntry type="library" scope="TEST" name="junit" level="project" />
</component>
</module>
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index db4c6dc6..d0e431a 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -25,14 +25,9 @@
import com.android.internal.util.XmlUtils;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
-import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
-import com.android.layoutlib.bridge.impl.ParserFactory;
import com.android.layoutlib.bridge.impl.ResourceHelper;
import com.android.resources.ResourceType;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import android.annotation.Nullable;
import android.content.res.Resources.NotFoundException;
import android.content.res.Resources.Theme;
@@ -42,7 +37,6 @@
import android.view.LayoutInflater_Delegate;
import android.view.ViewGroup.LayoutParams;
-import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
@@ -71,7 +65,7 @@
*/
public final class BridgeTypedArray extends TypedArray {
- private final BridgeResources mBridgeResources;
+ private final Resources mBridgeResources;
private final BridgeContext mContext;
private final boolean mPlatformFile;
@@ -84,7 +78,7 @@
@Nullable
private int[] mEmptyIds;
- public BridgeTypedArray(BridgeResources resources, BridgeContext context, int len,
+ public BridgeTypedArray(Resources resources, BridgeContext context, int len,
boolean platformFile) {
super(resources, null, null, 0);
mBridgeResources = resources;
@@ -305,71 +299,22 @@
return defValue;
}
- /**
- * Retrieve the ColorStateList for the attribute at <var>index</var>.
- * The value may be either a single solid color or a reference to
- * a color or complex {@link android.content.res.ColorStateList} description.
- *
- * @param index Index of attribute to retrieve.
- *
- * @return ColorStateList for the attribute, or null if not defined.
- */
@Override
public ColorStateList getColorStateList(int index) {
if (!hasValue(index)) {
return null;
}
- ResourceValue resValue = mResourceData[index];
- String value = resValue.getValue();
+ return ResourceHelper.getColorStateList(mResourceData[index], mContext);
+ }
- if (value == null) {
+ @Override
+ public ComplexColor getComplexColor(int index) {
+ if (!hasValue(index)) {
return null;
}
-
- try {
- // Get the state list file content from callback to parse PSI file
- XmlPullParser parser = mContext.getLayoutlibCallback().getXmlFileParser(value);
- if (parser == null) {
- // If used with a version of Android Studio that does not implement getXmlFileParser
- // fall back to reading the file from disk
- File f = new File(value);
- if (f.isFile()) {
- parser = ParserFactory.create(f);
- }
- }
- if (parser != null) {
- BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
- parser, mContext, resValue.isFramework());
- try {
- return ColorStateList.createFromXml(mContext.getResources(), blockParser,
- mContext.getTheme());
- } finally {
- blockParser.ensurePopped();
- }
- }
- } catch (XmlPullParserException e) {
- Bridge.getLog().error(LayoutLog.TAG_BROKEN,
- "Failed to configure parser for " + value, e, null);
- return null;
- } catch (Exception e) {
- // this is an error and not warning since the file existence is checked before
- // attempting to parse it.
- Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
- "Failed to parse file " + value, e, null);
-
- return null;
- }
-
- try {
- int color = ResourceHelper.getColor(value);
- return ColorStateList.valueOf(color);
- } catch (NumberFormatException e) {
- Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e, null);
- }
-
- return null;
+ return ResourceHelper.getComplexColor(mResourceData[index], mContext);
}
/**
@@ -756,7 +701,8 @@
if (resVal instanceof ArrayResourceValue) {
ArrayResourceValue array = (ArrayResourceValue) resVal;
int count = array.getElementCount();
- return count >= 0 ? mBridgeResources.fillValues(array, new CharSequence[count]) : null;
+ return count >= 0 ? Resources_Delegate.fillValues(mBridgeResources, array, new CharSequence[count]) :
+ null;
}
int id = getResourceId(index, 0);
String resIdMessage = id > 0 ? " (resource id 0x" + Integer.toHexString(id) + ')' : "";
@@ -1004,7 +950,6 @@
}
static TypedArray obtain(Resources res, int len) {
- return res instanceof BridgeResources ?
- new BridgeTypedArray(((BridgeResources) res), null, len, true) : null;
+ return new BridgeTypedArray(res, null, len, true);
}
}
diff --git a/tools/layoutlib/bridge/src/android/content/res/ComplexColor_Accessor.java b/tools/layoutlib/bridge/src/android/content/res/ComplexColor_Accessor.java
new file mode 100644
index 0000000..09c0260
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/content/res/ComplexColor_Accessor.java
@@ -0,0 +1,46 @@
+/*
+ * 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 org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.Resources.Theme;
+import android.util.AttributeSet;
+
+import java.io.IOException;
+
+/**
+ * Class that provides access to the {@link GradientColor#createFromXmlInner(Resources,
+ * XmlPullParser, AttributeSet, Theme)} and {@link ColorStateList#createFromXmlInner(Resources,
+ * XmlPullParser, AttributeSet, Theme)} methods
+ */
+public class ComplexColor_Accessor {
+ public static GradientColor createGradientColorFromXmlInner(@NonNull Resources r,
+ @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
+ throws IOException, XmlPullParserException {
+ return GradientColor.createFromXmlInner(r, parser, attrs, theme);
+ }
+
+ public static ColorStateList createColorStateListFromXmlInner(@NonNull Resources r,
+ @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
+ throws IOException, XmlPullParserException {
+ return ColorStateList.createFromXmlInner(r, parser, attrs, theme);
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
similarity index 63%
rename from tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
rename to tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
index fe46480..985dd5a 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 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.
@@ -28,8 +28,10 @@
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.layoutlib.bridge.impl.ParserFactory;
import com.android.layoutlib.bridge.impl.ResourceHelper;
+import com.android.layoutlib.bridge.util.NinePatchInputStream;
import com.android.ninepatch.NinePatch;
import com.android.resources.ResourceType;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import com.android.util.Pair;
import org.xmlpull.v1.XmlPullParser;
@@ -37,6 +39,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.res.Resources.NotFoundException;
+import android.content.res.Resources.Theme;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
@@ -50,132 +54,101 @@
import java.util.Iterator;
@SuppressWarnings("deprecation")
-public final class BridgeResources extends Resources {
+public class Resources_Delegate {
- private BridgeContext mContext;
- private LayoutlibCallback mLayoutlibCallback;
- private boolean[] mPlatformResourceFlag = new boolean[1];
- private TypedValue mTmpValue = new TypedValue();
+ private static boolean[] mPlatformResourceFlag = new boolean[1];
- /**
- * Simpler wrapper around FileInputStream. This is used when the input stream represent
- * not a normal bitmap but a nine patch.
- * This is useful when the InputStream is created in a method but used in another that needs
- * to know whether this is 9-patch or not, such as BitmapFactory.
- */
- public class NinePatchInputStream extends FileInputStream {
- private boolean mFakeMarkSupport = true;
- public NinePatchInputStream(File file) throws FileNotFoundException {
- super(file);
- }
-
- @Override
- public boolean markSupported() {
- //noinspection SimplifiableIfStatement
- if (mFakeMarkSupport) {
- // this is needed so that BitmapFactory doesn't wrap this in a BufferedInputStream.
- return true;
- }
-
- return super.markSupported();
- }
-
- public void disableFakeMarkSupport() {
- // disable fake mark support so that in case codec actually try to use them
- // we don't lie to them.
- mFakeMarkSupport = false;
- }
- }
-
- /**
- * This initializes the static field {@link Resources#mSystem} which is used
- * by methods who get global resources using {@link Resources#getSystem()}.
- * <p/>
- * They will end up using our bridge resources.
- * <p/>
- * {@link Bridge} calls this method after setting up a new bridge.
- */
public static Resources initSystem(BridgeContext context,
AssetManager assets,
DisplayMetrics metrics,
Configuration config,
LayoutlibCallback layoutlibCallback) {
- return Resources.mSystem = new BridgeResources(context,
- assets,
- metrics,
- config,
- layoutlibCallback);
+ Resources resources = new Resources(assets, metrics, config);
+ resources.mContext = context;
+ resources.mLayoutlibCallback = layoutlibCallback;
+ return Resources.mSystem = resources;
}
/**
- * Disposes the static {@link Resources#mSystem} to make sure we don't leave objects
- * around that would prevent us from unloading the library.
+ * Disposes the static {@link Resources#mSystem} to make sure we don't leave objects around that
+ * would prevent us from unloading the library.
*/
public static void disposeSystem() {
- if (Resources.mSystem instanceof BridgeResources) {
- ((BridgeResources)(Resources.mSystem)).mContext = null;
- ((BridgeResources)(Resources.mSystem)).mLayoutlibCallback = null;
- }
+ Resources.mSystem.mContext = null;
+ Resources.mSystem.mLayoutlibCallback = null;
Resources.mSystem = null;
}
- private BridgeResources(BridgeContext context, AssetManager assets, DisplayMetrics metrics,
- Configuration config, LayoutlibCallback layoutlibCallback) {
- super(assets, metrics, config);
- mContext = context;
- mLayoutlibCallback = layoutlibCallback;
+ public static BridgeTypedArray newTypeArray(Resources resources, int numEntries,
+ boolean platformFile) {
+ return new BridgeTypedArray(resources, resources.mContext, numEntries, platformFile);
}
- public BridgeTypedArray newTypeArray(int numEntries, boolean platformFile) {
- return new BridgeTypedArray(this, mContext, numEntries, platformFile);
- }
-
- private Pair<String, ResourceValue> getResourceValue(int id, boolean[] platformResFlag_out) {
+ private static Pair<String, ResourceValue> getResourceValue(Resources resources, int id,
+ boolean[] platformResFlag_out) {
// first get the String related to this id in the framework
Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
+ // Set the layoutlib callback and context for resources
+ if (resources != Resources.mSystem && resources.mLayoutlibCallback == null) {
+ resources.mLayoutlibCallback = Resources.mSystem.mLayoutlibCallback;
+ resources.mContext = Resources.mSystem.mContext;
+ }
+
if (resourceInfo != null) {
platformResFlag_out[0] = true;
String attributeName = resourceInfo.getSecond();
- return Pair.of(attributeName, mContext.getRenderResources().getFrameworkResource(
- resourceInfo.getFirst(), attributeName));
+ return Pair.of(attributeName,
+ resources.mContext.getRenderResources().getFrameworkResource(
+ resourceInfo.getFirst(), attributeName));
}
// didn't find a match in the framework? look in the project.
- if (mLayoutlibCallback != null) {
- resourceInfo = mLayoutlibCallback.resolveResourceId(id);
+ if (resources.mLayoutlibCallback != null) {
+ resourceInfo = resources.mLayoutlibCallback.resolveResourceId(id);
if (resourceInfo != null) {
platformResFlag_out[0] = false;
String attributeName = resourceInfo.getSecond();
- return Pair.of(attributeName, mContext.getRenderResources().getProjectResource(
- resourceInfo.getFirst(), attributeName));
+ return Pair.of(attributeName,
+ resources.mContext.getRenderResources().getProjectResource(
+ resourceInfo.getFirst(), attributeName));
}
}
return null;
}
- @Override
- public Drawable getDrawable(int id, Theme theme) {
- Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
+ @LayoutlibDelegate
+ static Drawable getDrawable(Resources resources, int id) {
+ return getDrawable(resources, id, null);
+ }
+
+ @LayoutlibDelegate
+ static Drawable getDrawable(Resources resources, int id, Theme theme) {
+ Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
if (value != null) {
- return ResourceHelper.getDrawable(value.getSecond(), mContext, theme);
+ return ResourceHelper.getDrawable(value.getSecond(), resources.mContext, theme);
}
// id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
+ throwException(resources, id);
// this is not used since the method above always throws
return null;
}
- @Override
- public int getColor(int id, Theme theme) throws NotFoundException {
- Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
+ @LayoutlibDelegate
+ static int getColor(Resources resources, int id) {
+ return getColor(resources, id, null);
+ }
+
+ @LayoutlibDelegate
+ static int getColor(Resources resources, int id, Theme theme) throws NotFoundException {
+ Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
if (value != null) {
ResourceValue resourceValue = value.getSecond();
@@ -187,7 +160,7 @@
String message;
if (new File(resourceValue.getValue()).isFile()) {
String resource = (resourceValue.isFramework() ? "@android:" : "@") + "color/"
- + resourceValue.getName();
+ + resourceValue.getName();
message = "Hexadecimal color expected, found Color State List for " + resource;
} else {
message = e.getMessage();
@@ -200,31 +173,57 @@
// Suppress possible NPE. getColorStateList will never return null, it will instead
// throw an exception, but intelliJ can't figure that out
//noinspection ConstantConditions
- return getColorStateList(id, theme).getDefaultColor();
+ return getColorStateList(resources, id, theme).getDefaultColor();
}
- @Override
- public ColorStateList getColorStateList(int id, Theme theme) throws NotFoundException {
- Pair<String, ResourceValue> resValue = getResourceValue(id, mPlatformResourceFlag);
+ @LayoutlibDelegate
+ static ColorStateList getColorStateList(Resources resources, int id) throws NotFoundException {
+ return getColorStateList(resources, id, null);
+ }
+
+ @LayoutlibDelegate
+ static ColorStateList getColorStateList(Resources resources, int id, Theme theme)
+ throws NotFoundException {
+ Pair<String, ResourceValue> resValue =
+ getResourceValue(resources, id, mPlatformResourceFlag);
if (resValue != null) {
ColorStateList stateList = ResourceHelper.getColorStateList(resValue.getSecond(),
- mContext);
+ resources.mContext);
if (stateList != null) {
return stateList.obtainForTheme(theme);
}
}
// id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
+ throwException(resources, id);
// this is not used since the method above always throws
return null;
}
- @Override
- public CharSequence getText(int id) throws NotFoundException {
- Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
+ @LayoutlibDelegate
+ static CharSequence getText(Resources resources, int id, CharSequence def) {
+ Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
+
+ if (value != null) {
+ ResourceValue resValue = value.getSecond();
+
+ assert resValue != null;
+ if (resValue != null) {
+ String v = resValue.getValue();
+ if (v != null) {
+ return v;
+ }
+ }
+ }
+
+ return def;
+ }
+
+ @LayoutlibDelegate
+ static CharSequence getText(Resources resources, int id) throws NotFoundException {
+ Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
if (value != null) {
ResourceValue resValue = value.getSecond();
@@ -239,38 +238,38 @@
}
// id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
+ throwException(resources, id);
// this is not used since the method above always throws
return null;
}
- @Override
- public CharSequence[] getTextArray(int id) throws NotFoundException {
- ResourceValue resValue = getArrayResourceValue(id);
+ @LayoutlibDelegate
+ static CharSequence[] getTextArray(Resources resources, int id) throws NotFoundException {
+ ResourceValue resValue = getArrayResourceValue(resources, id);
if (resValue == null) {
// Error already logged by getArrayResourceValue.
return new CharSequence[0];
} else if (!(resValue instanceof ArrayResourceValue)) {
return new CharSequence[]{
- resolveReference(resValue.getValue(), resValue.isFramework())};
+ resolveReference(resources, resValue.getValue(), resValue.isFramework())};
}
ArrayResourceValue arv = ((ArrayResourceValue) resValue);
- return fillValues(arv, new CharSequence[arv.getElementCount()]);
+ return fillValues(resources, arv, new CharSequence[arv.getElementCount()]);
}
- @Override
- public String[] getStringArray(int id) throws NotFoundException {
- ResourceValue resValue = getArrayResourceValue(id);
+ @LayoutlibDelegate
+ static String[] getStringArray(Resources resources, int id) throws NotFoundException {
+ ResourceValue resValue = getArrayResourceValue(resources, id);
if (resValue == null) {
// Error already logged by getArrayResourceValue.
return new String[0];
} else if (!(resValue instanceof ArrayResourceValue)) {
return new String[]{
- resolveReference(resValue.getValue(), resValue.isFramework())};
+ resolveReference(resources, resValue.getValue(), resValue.isFramework())};
}
ArrayResourceValue arv = ((ArrayResourceValue) resValue);
- return fillValues(arv, new String[arv.getElementCount()]);
+ return fillValues(resources, arv, new String[arv.getElementCount()]);
}
/**
@@ -278,25 +277,26 @@
* always Strings. The ideal signature for the method should be <T super String>, but java
* generics don't support it.
*/
- <T extends CharSequence> T[] fillValues(ArrayResourceValue resValue, T[] values) {
+ static <T extends CharSequence> T[] fillValues(Resources resources, ArrayResourceValue resValue,
+ T[] values) {
int i = 0;
for (Iterator<String> iterator = resValue.iterator(); iterator.hasNext(); i++) {
@SuppressWarnings("unchecked")
- T s = (T) resolveReference(iterator.next(), resValue.isFramework());
+ T s = (T) resolveReference(resources, iterator.next(), resValue.isFramework());
values[i] = s;
}
return values;
}
- @Override
- public int[] getIntArray(int id) throws NotFoundException {
- ResourceValue rv = getArrayResourceValue(id);
+ @LayoutlibDelegate
+ static int[] getIntArray(Resources resources, int id) throws NotFoundException {
+ ResourceValue rv = getArrayResourceValue(resources, id);
if (rv == null) {
// Error already logged by getArrayResourceValue.
return new int[0];
} else if (!(rv instanceof ArrayResourceValue)) {
// This is an older IDE that can only give us the first element of the array.
- String firstValue = resolveReference(rv.getValue(), rv.isFramework());
+ String firstValue = resolveReference(resources, rv.getValue(), rv.isFramework());
try {
return new int[]{getInt(firstValue)};
} catch (NumberFormatException e) {
@@ -310,7 +310,7 @@
int[] values = new int[resValue.getElementCount()];
int i = 0;
for (Iterator<String> iterator = resValue.iterator(); iterator.hasNext(); i++) {
- String element = resolveReference(iterator.next(), resValue.isFramework());
+ String element = resolveReference(resources, iterator.next(), resValue.isFramework());
try {
values[i] = getInt(element);
} catch (NumberFormatException e) {
@@ -330,11 +330,13 @@
* method returns the ResourceValue. This happens on older versions of the IDE, which did not
* parse the array resources properly.
* <p/>
+ *
* @throws NotFoundException if no resource if found
*/
@Nullable
- private ResourceValue getArrayResourceValue(int id) throws NotFoundException {
- Pair<String, ResourceValue> v = getResourceValue(id, mPlatformResourceFlag);
+ private static ResourceValue getArrayResourceValue(Resources resources, int id)
+ throws NotFoundException {
+ Pair<String, ResourceValue> v = getResourceValue(resources, id, mPlatformResourceFlag);
if (v != null) {
ResourceValue resValue = v.getSecond();
@@ -360,19 +362,20 @@
}
// id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
+ throwException(resources, id);
// this is not used since the method above always throws
return null;
}
@NonNull
- private String resolveReference(@NonNull String ref, boolean forceFrameworkOnly) {
+ private static String resolveReference(Resources resources, @NonNull String ref,
+ boolean forceFrameworkOnly) {
if (ref.startsWith(SdkConstants.PREFIX_RESOURCE_REF) || ref.startsWith
(SdkConstants.PREFIX_THEME_REF)) {
ResourceValue rv =
- mContext.getRenderResources().findResValue(ref, forceFrameworkOnly);
- rv = mContext.getRenderResources().resolveResValue(rv);
+ resources.mContext.getRenderResources().findResValue(ref, forceFrameworkOnly);
+ rv = resources.mContext.getRenderResources().resolveResValue(rv);
if (rv != null) {
return rv.getValue();
} else {
@@ -384,9 +387,9 @@
return ref;
}
- @Override
- public XmlResourceParser getLayout(int id) throws NotFoundException {
- Pair<String, ResourceValue> v = getResourceValue(id, mPlatformResourceFlag);
+ @LayoutlibDelegate
+ static XmlResourceParser getLayout(Resources resources, int id) throws NotFoundException {
+ Pair<String, ResourceValue> v = getResourceValue(resources, id, mPlatformResourceFlag);
if (v != null) {
ResourceValue value = v.getSecond();
@@ -394,8 +397,8 @@
try {
// check if the current parser can provide us with a custom parser.
- if (mPlatformResourceFlag[0] == false) {
- parser = mLayoutlibCallback.getParser(value);
+ if (!mPlatformResourceFlag[0]) {
+ parser = resources.mLayoutlibCallback.getParser(value);
}
// create a new one manually if needed.
@@ -409,7 +412,8 @@
}
if (parser != null) {
- return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
+ return new BridgeXmlBlockParser(parser, resources.mContext,
+ mPlatformResourceFlag[0]);
}
} catch (XmlPullParserException e) {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
@@ -422,19 +426,19 @@
}
// id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
+ throwException(resources, id);
// this is not used since the method above always throws
return null;
}
- @Override
- public XmlResourceParser getAnimation(int id) throws NotFoundException {
- Pair<String, ResourceValue> v = getResourceValue(id, mPlatformResourceFlag);
+ @LayoutlibDelegate
+ static XmlResourceParser getAnimation(Resources resources, int id) throws NotFoundException {
+ Pair<String, ResourceValue> v = getResourceValue(resources, id, mPlatformResourceFlag);
if (v != null) {
ResourceValue value = v.getSecond();
- XmlPullParser parser = null;
+ XmlPullParser parser;
try {
File xml = new File(value.getValue());
@@ -443,7 +447,8 @@
// give that to our XmlBlockParser
parser = ParserFactory.create(xml);
- return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
+ return new BridgeXmlBlockParser(parser, resources.mContext,
+ mPlatformResourceFlag[0]);
}
} catch (XmlPullParserException e) {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
@@ -456,26 +461,31 @@
}
// id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
+ throwException(resources, id);
// this is not used since the method above always throws
return null;
}
- @Override
- public TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
- return mContext.obtainStyledAttributes(set, attrs);
+ @LayoutlibDelegate
+ static TypedArray obtainAttributes(Resources resources, AttributeSet set, int[] attrs) {
+ return resources.mContext.obtainStyledAttributes(set, attrs);
}
- @Override
- public TypedArray obtainTypedArray(int id) throws NotFoundException {
+ @LayoutlibDelegate
+ static TypedArray obtainAttributes(Resources resources, Resources.Theme theme, AttributeSet
+ set, int[] attrs) {
+ return Resources.obtainAttributes_Original(resources, theme, set, attrs);
+ }
+
+ @LayoutlibDelegate
+ static TypedArray obtainTypedArray(Resources resources, int id) throws NotFoundException {
throw new UnsupportedOperationException();
}
-
- @Override
- public float getDimension(int id) throws NotFoundException {
- Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
+ @LayoutlibDelegate
+ static float getDimension(Resources resources, int id) throws NotFoundException {
+ Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
if (value != null) {
ResourceValue resValue = value.getSecond();
@@ -490,26 +500,26 @@
} else if (v.equals(BridgeConstants.WRAP_CONTENT)) {
return LayoutParams.WRAP_CONTENT;
}
-
+ TypedValue tmpValue = new TypedValue();
if (ResourceHelper.parseFloatAttribute(
- value.getFirst(), v, mTmpValue, true /*requireUnit*/) &&
- mTmpValue.type == TypedValue.TYPE_DIMENSION) {
- return mTmpValue.getDimension(getDisplayMetrics());
+ value.getFirst(), v, tmpValue, true /*requireUnit*/) &&
+ tmpValue.type == TypedValue.TYPE_DIMENSION) {
+ return tmpValue.getDimension(resources.getDisplayMetrics());
}
}
}
}
// id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
+ throwException(resources, id);
// this is not used since the method above always throws
return 0;
}
- @Override
- public int getDimensionPixelOffset(int id) throws NotFoundException {
- Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
+ @LayoutlibDelegate
+ static int getDimensionPixelOffset(Resources resources, int id) throws NotFoundException {
+ Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
if (value != null) {
ResourceValue resValue = value.getSecond();
@@ -518,26 +528,27 @@
if (resValue != null) {
String v = resValue.getValue();
if (v != null) {
+ TypedValue tmpValue = new TypedValue();
if (ResourceHelper.parseFloatAttribute(
- value.getFirst(), v, mTmpValue, true /*requireUnit*/) &&
- mTmpValue.type == TypedValue.TYPE_DIMENSION) {
- return TypedValue.complexToDimensionPixelOffset(mTmpValue.data,
- getDisplayMetrics());
+ value.getFirst(), v, tmpValue, true /*requireUnit*/) &&
+ tmpValue.type == TypedValue.TYPE_DIMENSION) {
+ return TypedValue.complexToDimensionPixelOffset(tmpValue.data,
+ resources.getDisplayMetrics());
}
}
}
}
// id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
+ throwException(resources, id);
// this is not used since the method above always throws
return 0;
}
- @Override
- public int getDimensionPixelSize(int id) throws NotFoundException {
- Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
+ @LayoutlibDelegate
+ static int getDimensionPixelSize(Resources resources, int id) throws NotFoundException {
+ Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
if (value != null) {
ResourceValue resValue = value.getSecond();
@@ -546,26 +557,27 @@
if (resValue != null) {
String v = resValue.getValue();
if (v != null) {
+ TypedValue tmpValue = new TypedValue();
if (ResourceHelper.parseFloatAttribute(
- value.getFirst(), v, mTmpValue, true /*requireUnit*/) &&
- mTmpValue.type == TypedValue.TYPE_DIMENSION) {
- return TypedValue.complexToDimensionPixelSize(mTmpValue.data,
- getDisplayMetrics());
+ value.getFirst(), v, tmpValue, true /*requireUnit*/) &&
+ tmpValue.type == TypedValue.TYPE_DIMENSION) {
+ return TypedValue.complexToDimensionPixelSize(tmpValue.data,
+ resources.getDisplayMetrics());
}
}
}
}
// id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
+ throwException(resources, id);
// this is not used since the method above always throws
return 0;
}
- @Override
- public int getInteger(int id) throws NotFoundException {
- Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
+ @LayoutlibDelegate
+ static int getInteger(Resources resources, int id) throws NotFoundException {
+ Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
if (value != null) {
ResourceValue resValue = value.getSecond();
@@ -584,15 +596,15 @@
}
// id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
+ throwException(resources, id);
// this is not used since the method above always throws
return 0;
}
- @Override
- public boolean getBoolean(int id) throws NotFoundException {
- Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
+ @LayoutlibDelegate
+ static boolean getBoolean(Resources resources, int id) throws NotFoundException {
+ Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
if (value != null) {
ResourceValue resValue = value.getSecond();
@@ -606,61 +618,62 @@
}
// id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
+ throwException(resources, id);
// this is not used since the method above always throws
return false;
}
- @Override
- public String getResourceEntryName(int resid) throws NotFoundException {
+ @LayoutlibDelegate
+ static String getResourceEntryName(Resources resources, int resid) throws NotFoundException {
throw new UnsupportedOperationException();
}
- @Override
- public String getResourceName(int resid) throws NotFoundException {
+ @LayoutlibDelegate
+ static String getResourceName(Resources resources, int resid) throws NotFoundException {
throw new UnsupportedOperationException();
}
- @Override
- public String getResourceTypeName(int resid) throws NotFoundException {
+ @LayoutlibDelegate
+ static String getResourceTypeName(Resources resources, int resid) throws NotFoundException {
throw new UnsupportedOperationException();
}
- @Override
- public String getString(int id, Object... formatArgs) throws NotFoundException {
- String s = getString(id);
+ @LayoutlibDelegate
+ static String getString(Resources resources, int id, Object... formatArgs)
+ throws NotFoundException {
+ String s = getString(resources, id);
if (s != null) {
return String.format(s, formatArgs);
}
// id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
+ throwException(resources, id);
// this is not used since the method above always throws
return null;
}
- @Override
- public String getString(int id) throws NotFoundException {
- Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
+ @LayoutlibDelegate
+ static String getString(Resources resources, int id) throws NotFoundException {
+ Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
if (value != null && value.getSecond().getValue() != null) {
return value.getSecond().getValue();
}
// id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
+ throwException(resources, id);
// this is not used since the method above always throws
return null;
}
- @Override
- public void getValue(int id, TypedValue outValue, boolean resolveRefs)
+ @LayoutlibDelegate
+ static void getValue(Resources resources, int id, TypedValue outValue, boolean resolveRefs)
throws NotFoundException {
- Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
+ Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
if (value != null) {
ResourceValue resVal = value.getSecond();
@@ -673,7 +686,7 @@
}
if (resVal instanceof DensityBasedResourceValue) {
outValue.density =
- ((DensityBasedResourceValue) resVal).getResourceDensity().getDpiValue();
+ ((DensityBasedResourceValue) resVal).getResourceDensity().getDpiValue();
}
// else it's a string
@@ -684,18 +697,18 @@
}
// id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
+ throwException(resources, id);
}
- @Override
- public void getValue(String name, TypedValue outValue, boolean resolveRefs)
+ @LayoutlibDelegate
+ static void getValue(Resources resources, String name, TypedValue outValue, boolean resolveRefs)
throws NotFoundException {
throw new UnsupportedOperationException();
}
- @Override
- public XmlResourceParser getXml(int id) throws NotFoundException {
- Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
+ @LayoutlibDelegate
+ static XmlResourceParser getXml(Resources resources, int id) throws NotFoundException {
+ Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
if (value != null) {
String v = value.getSecond().getValue();
@@ -707,7 +720,8 @@
try {
XmlPullParser parser = ParserFactory.create(f);
- return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
+ return new BridgeXmlBlockParser(parser, resources.mContext,
+ mPlatformResourceFlag[0]);
} catch (XmlPullParserException e) {
NotFoundException newE = new NotFoundException();
newE.initCause(e);
@@ -722,25 +736,31 @@
}
// id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
+ throwException(resources, id);
// this is not used since the method above always throws
return null;
}
- @Override
- public XmlResourceParser loadXmlResourceParser(String file, int id,
+ @LayoutlibDelegate
+ static XmlResourceParser loadXmlResourceParser(Resources resources, int id,
+ String type) throws NotFoundException {
+ return resources.loadXmlResourceParser_Original(id, type);
+ }
+
+ @LayoutlibDelegate
+ static XmlResourceParser loadXmlResourceParser(Resources resources, String file, int id,
int assetCookie, String type) throws NotFoundException {
// even though we know the XML file to load directly, we still need to resolve the
// id so that we can know if it's a platform or project resource.
// (mPlatformResouceFlag will get the result and will be used later).
- getResourceValue(id, mPlatformResourceFlag);
+ getResourceValue(resources, id, mPlatformResourceFlag);
File f = new File(file);
try {
XmlPullParser parser = ParserFactory.create(f);
- return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
+ return new BridgeXmlBlockParser(parser, resources.mContext, mPlatformResourceFlag[0]);
} catch (XmlPullParserException e) {
NotFoundException newE = new NotFoundException();
newE.initCause(e);
@@ -752,9 +772,9 @@
}
}
- @Override
- public InputStream openRawResource(int id) throws NotFoundException {
- Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
+ @LayoutlibDelegate
+ static InputStream openRawResource(Resources resources, int id) throws NotFoundException {
+ Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
if (value != null) {
String path = value.getSecond().getValue();
@@ -781,15 +801,16 @@
}
// id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
+ throwException(resources, id);
// this is not used since the method above always throws
return null;
}
- @Override
- public InputStream openRawResource(int id, TypedValue value) throws NotFoundException {
- getValue(id, value, true);
+ @LayoutlibDelegate
+ static InputStream openRawResource(Resources resources, int id, TypedValue value) throws
+ NotFoundException {
+ getValue(resources, id, value, true);
String path = value.string.toString();
@@ -813,23 +834,27 @@
throw new NotFoundException();
}
- @Override
- public AssetFileDescriptor openRawResourceFd(int id) throws NotFoundException {
+ @LayoutlibDelegate
+ static AssetFileDescriptor openRawResourceFd(Resources resources, int id) throws
+ NotFoundException {
throw new UnsupportedOperationException();
}
/**
- * Builds and throws a {@link Resources.NotFoundException} based on a resource id and a resource type.
+ * Builds and throws a {@link Resources.NotFoundException} based on a resource id and a resource
+ * type.
+ *
* @param id the id of the resource
+ *
* @throws NotFoundException
*/
- private void throwException(int id) throws NotFoundException {
+ private static void throwException(Resources resources, int id) throws NotFoundException {
// first get the String related to this id in the framework
Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
// if the name is unknown in the framework, get it from the custom view loader.
- if (resourceInfo == null && mLayoutlibCallback != null) {
- resourceInfo = mLayoutlibCallback.resolveResourceId(id);
+ if (resourceInfo == null && resources.mLayoutlibCallback != null) {
+ resourceInfo = resources.mLayoutlibCallback.resolveResourceId(id);
}
String message;
@@ -845,7 +870,7 @@
throw new NotFoundException(message);
}
- private int getInt(String v) throws NumberFormatException {
+ private static int getInt(String v) throws NumberFormatException {
int radix = 10;
if (v.startsWith("0x")) {
v = v.substring(2);
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
index 8d5863b..8bd2a7a 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
@@ -23,7 +23,7 @@
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.annotation.Nullable;
-import android.content.res.BridgeResources.NinePatchInputStream;
+import com.android.layoutlib.bridge.util.NinePatchInputStream;
import android.graphics.BitmapFactory.Options;
import android.graphics.Bitmap_Delegate.BitmapCreateFlags;
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..33296e1 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -223,6 +223,14 @@
return mColorFilter;
}
+ public void setColorFilter(long colorFilterPtr) {
+ mColorFilter = ColorFilter_Delegate.getDelegate(colorFilterPtr);
+ }
+
+ public void setShader(long shaderPtr) {
+ mShader = Shader_Delegate.getDelegate(shaderPtr);
+ }
+
/**
* 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/AnimatedVectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java
new file mode 100644
index 0000000..200fe3b
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java
@@ -0,0 +1,284 @@
+/*
+ * 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.ide.common.rendering.api.LayoutLog;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper_Delegate;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.drawable.AnimatedVectorDrawable.VectorDrawableAnimatorRT;
+import android.graphics.drawable.VectorDrawable_Delegate.VFullPath_Delegate;
+import android.graphics.drawable.VectorDrawable_Delegate.VGroup_Delegate;
+import android.graphics.drawable.VectorDrawable_Delegate.VNativeObject;
+import android.graphics.drawable.VectorDrawable_Delegate.VPathRenderer_Delegate;
+
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link
+ * AnimatedVectorDrawable}
+ * <p>
+ * Through the layoutlib_create tool, the original methods of AnimatedVectorDrawable have been
+ * replaced by calls to methods of the same name in this delegate class.
+ */
+@SuppressWarnings("unused")
+public class AnimatedVectorDrawable_Delegate {
+ private static DelegateManager<AnimatorSetHolder> sAnimatorSets = new
+ DelegateManager<>(AnimatorSetHolder.class);
+ private static DelegateManager<PropertySetter> sHolders = new
+ DelegateManager<>(PropertySetter.class);
+
+
+ @LayoutlibDelegate
+ /*package*/ static long nCreateAnimatorSet() {
+ return sAnimatorSets.addNewDelegate(new AnimatorSetHolder());
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nAddAnimator(long setPtr, long propertyValuesHolder,
+ long nativeInterpolator, long startDelay, long duration, int repeatCount) {
+ PropertySetter holder = sHolders.getDelegate(propertyValuesHolder);
+ if (holder == null || holder.getValues() == null) {
+ return;
+ }
+
+ ObjectAnimator animator = new ObjectAnimator();
+ animator.setValues(holder.getValues());
+ animator.setInterpolator(
+ NativeInterpolatorFactoryHelper_Delegate.getDelegate(nativeInterpolator));
+ animator.setStartDelay(startDelay);
+ animator.setDuration(duration);
+ animator.setRepeatCount(repeatCount);
+ animator.setTarget(holder);
+ animator.setPropertyName(holder.getValues().getPropertyName());
+
+ AnimatorSetHolder set = sAnimatorSets.getDelegate(setPtr);
+ assert set != null;
+ set.addAnimator(animator);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long nCreateGroupPropertyHolder(long nativePtr, int propertyId,
+ float startValue, float endValue) {
+ VGroup_Delegate group = VNativeObject.getDelegate(nativePtr);
+ Consumer<Float> setter = group.getPropertySetter(propertyId);
+
+ return sHolders.addNewDelegate(FloatPropertySetter.of(setter, startValue,
+ endValue));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long nCreatePathDataPropertyHolder(long nativePtr, long startValuePtr,
+ long endValuePtr) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, "AnimatedVectorDrawable path " +
+ "animations are not supported.", null, null);
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long nCreatePathColorPropertyHolder(long nativePtr, int propertyId,
+ int startValue, int endValue) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(nativePtr);
+ Consumer<Integer> setter = path.getIntPropertySetter(propertyId);
+
+ return sHolders.addNewDelegate(IntPropertySetter.of(setter, startValue,
+ endValue));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long nCreatePathPropertyHolder(long nativePtr, int propertyId,
+ float startValue, float endValue) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(nativePtr);
+ Consumer<Float> setter = path.getFloatPropertySetter(propertyId);
+
+ return sHolders.addNewDelegate(FloatPropertySetter.of(setter, startValue,
+ endValue));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue,
+ float endValue) {
+ VPathRenderer_Delegate renderer = VNativeObject.getDelegate(nativePtr);
+
+ return sHolders.addNewDelegate(FloatPropertySetter.of(renderer::setRootAlpha,
+ startValue,
+ endValue));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nSetPropertyHolderData(long nativePtr, float[] data, int length) {
+ PropertySetter setter = sHolders.getDelegate(nativePtr);
+ assert setter != null;
+
+ setter.setValues(data);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nStart(long animatorSetPtr, VectorDrawableAnimatorRT set, int id) {
+ AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr);
+ assert animatorSet != null;
+
+ animatorSet.start();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nReverse(long animatorSetPtr, VectorDrawableAnimatorRT set, int id) {
+ AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr);
+ assert animatorSet != null;
+
+ animatorSet.reverse();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nEnd(long animatorSetPtr) {
+ AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr);
+ assert animatorSet != null;
+
+ animatorSet.end();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nReset(long animatorSetPtr) {
+ AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr);
+ assert animatorSet != null;
+
+ animatorSet.end();
+ animatorSet.start();
+ }
+
+ private static class AnimatorSetHolder {
+ private ArrayList<Animator> mAnimators = new ArrayList<>();
+ private AnimatorSet mAnimatorSet = null;
+
+ private void addAnimator(@NonNull Animator animator) {
+ mAnimators.add(animator);
+ }
+
+ private void ensureAnimatorSet() {
+ if (mAnimatorSet == null) {
+ mAnimatorSet = new AnimatorSet();
+ mAnimatorSet.playTogether(mAnimators);
+ }
+ }
+
+ private void start() {
+ ensureAnimatorSet();
+
+ mAnimatorSet.start();
+ }
+
+ private void end() {
+ mAnimatorSet.end();
+ }
+
+ private void reset() {
+ end();
+ start();
+ }
+
+ private void reverse() {
+ mAnimatorSet.reverse();
+ }
+ }
+
+ /**
+ * Class that allows setting a value and holds the range of values for the given property.
+ *
+ * @param <T> the type of the property
+ */
+ private static class PropertySetter<T> {
+ final Consumer<T> mValueSetter;
+ private PropertyValuesHolder mValues;
+
+ private PropertySetter(@NonNull Consumer<T> valueSetter) {
+ mValueSetter = valueSetter;
+ }
+
+ /**
+ * Method to set an {@link Integer} value for this property. The default implementation of
+ * this method doesn't do anything. This method is accessed via reflection by the
+ * PropertyValuesHolder.
+ */
+ public void setIntValue(Integer value) {
+ }
+
+ /**
+ * Method to set an {@link Integer} value for this property. The default implementation of
+ * this method doesn't do anything. This method is accessed via reflection by the
+ * PropertyValuesHolder.
+ */
+ public void setFloatValue(Float value) {
+ }
+
+ void setValues(float... values) {
+ mValues = PropertyValuesHolder.ofFloat("floatValue", values);
+ }
+
+ @Nullable
+ PropertyValuesHolder getValues() {
+ return mValues;
+ }
+
+ void setValues(int... values) {
+ mValues = PropertyValuesHolder.ofInt("intValue", values);
+ }
+ }
+
+ private static class IntPropertySetter extends PropertySetter<Integer> {
+ private IntPropertySetter(Consumer<Integer> valueSetter) {
+ super(valueSetter);
+ }
+
+ private static PropertySetter of(Consumer<Integer> valueSetter, int... values) {
+ PropertySetter setter = new IntPropertySetter(valueSetter);
+ setter.setValues(values);
+
+ return setter;
+ }
+
+ public void setIntValue(Integer value) {
+ mValueSetter.accept(value);
+ }
+ }
+
+ private static class FloatPropertySetter extends PropertySetter<Float> {
+ private FloatPropertySetter(Consumer<Float> valueSetter) {
+ super(valueSetter);
+ }
+
+ private static PropertySetter of(Consumer<Float> valueSetter, float... values) {
+ PropertySetter setter = new FloatPropertySetter(valueSetter);
+ setter.setValues(values);
+
+ return setter;
+ }
+
+ public void setFloatValue(Float value) {
+ mValueSetter.accept(value);
+ }
+
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate.java
new file mode 100644
index 0000000..3d78931
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate.java
@@ -0,0 +1,28 @@
+/*
+ * 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.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.drawable.AnimatedVectorDrawable.VectorDrawableAnimatorRT;
+
+public class AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate {
+ @LayoutlibDelegate
+ /*package*/ static boolean useLastSeenTarget(VectorDrawableAnimatorRT thisDrawableAnimator) {
+ return true;
+ }
+}
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..90b84f8
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
@@ -0,0 +1,1196 @@
+/*
+ * 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.annotation.NonNull;
+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 java.util.function.Consumer;
+
+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);
+
+ /**
+ * 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 = VNativeObject.getDelegate(rootGroupPtr);
+ return sPathManager.addNewDelegate(new VPathRenderer_Delegate(rootGroup));
+ }
+
+ @LayoutlibDelegate
+ static void nSetRendererViewportSize(long rendererPtr, float viewportWidth,
+ float viewportHeight) {
+ VPathRenderer_Delegate nativePathRenderer = VNativeObject.getDelegate(rendererPtr);
+ nativePathRenderer.mViewportWidth = viewportWidth;
+ nativePathRenderer.mViewportHeight = viewportHeight;
+ }
+
+ @LayoutlibDelegate
+ static boolean nSetRootAlpha(long rendererPtr, float alpha) {
+ VPathRenderer_Delegate nativePathRenderer = VNativeObject.getDelegate(rendererPtr);
+ nativePathRenderer.setRootAlpha(alpha);
+
+ return true;
+ }
+
+ @LayoutlibDelegate
+ static float nGetRootAlpha(long rendererPtr) {
+ VPathRenderer_Delegate nativePathRenderer = VNativeObject.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 = VNativeObject.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 = VNativeObject.getDelegate(nativeFullPathPtr);
+
+ return sPathManager.addNewDelegate(new VFullPath_Delegate(original));
+ }
+
+ @LayoutlibDelegate
+ static boolean nGetFullPathProperties(long pathPtr, byte[] propertiesData,
+ int length) {
+ VFullPath_Delegate path = VNativeObject.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 = VNativeObject.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) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+
+ path.setFillGradient(fillGradientPtr);
+ }
+
+ @LayoutlibDelegate
+ static void nUpdateFullPathStrokeGradient(long pathPtr, long strokeGradientPtr) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+
+ path.setStrokeGradient(strokeGradientPtr);
+ }
+
+ @LayoutlibDelegate
+ static long nCreateClipPath() {
+ return sPathManager.addNewDelegate(new VClipPath_Delegate());
+ }
+
+ @LayoutlibDelegate
+ static long nCreateClipPath(long clipPathPtr) {
+ VClipPath_Delegate original = VNativeObject.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 = VNativeObject.getDelegate(groupPtr);
+ return sPathManager.addNewDelegate(
+ new VGroup_Delegate(original, new ArrayMap<String, Object>()));
+ }
+
+ @LayoutlibDelegate
+ static void nSetName(long nodePtr, String name) {
+ VNativeObject group = VNativeObject.getDelegate(nodePtr);
+ group.setName(name);
+ }
+
+ @LayoutlibDelegate
+ static boolean nGetGroupProperties(long groupPtr, float[] propertiesData,
+ int length) {
+ VGroup_Delegate group = VNativeObject.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 = VNativeObject.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 = VNativeObject.getDelegate(groupPtr);
+ group.mChildren.add(VNativeObject.getDelegate(nodePtr));
+ }
+
+ @LayoutlibDelegate
+ static void nSetPathString(long pathPtr, String pathString, int length) {
+ VPath_Delegate path = VNativeObject.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 = VNativeObject.getDelegate(groupPtr);
+ return group.getRotation();
+ }
+
+ @LayoutlibDelegate
+ static void nSetRotation(long groupPtr, float rotation) {
+ VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+ group.setRotation(rotation);
+ }
+
+ @LayoutlibDelegate
+ static float nGetPivotX(long groupPtr) {
+ VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+ return group.getPivotX();
+ }
+
+ @LayoutlibDelegate
+ static void nSetPivotX(long groupPtr, float pivotX) {
+ VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+ group.setPivotX(pivotX);
+ }
+
+ @LayoutlibDelegate
+ static float nGetPivotY(long groupPtr) {
+ VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+ return group.getPivotY();
+ }
+
+ @LayoutlibDelegate
+ static void nSetPivotY(long groupPtr, float pivotY) {
+ VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+ group.setPivotY(pivotY);
+ }
+
+ @LayoutlibDelegate
+ static float nGetScaleX(long groupPtr) {
+ VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+ return group.getScaleX();
+ }
+
+ @LayoutlibDelegate
+ static void nSetScaleX(long groupPtr, float scaleX) {
+ VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+ group.setScaleX(scaleX);
+ }
+
+ @LayoutlibDelegate
+ static float nGetScaleY(long groupPtr) {
+ VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+ return group.getScaleY();
+ }
+
+ @LayoutlibDelegate
+ static void nSetScaleY(long groupPtr, float scaleY) {
+ VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+ group.setScaleY(scaleY);
+ }
+
+ @LayoutlibDelegate
+ static float nGetTranslateX(long groupPtr) {
+ VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+ return group.getTranslateX();
+ }
+
+ @LayoutlibDelegate
+ static void nSetTranslateX(long groupPtr, float translateX) {
+ VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+ group.setTranslateX(translateX);
+ }
+
+ @LayoutlibDelegate
+ static float nGetTranslateY(long groupPtr) {
+ VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+ return group.getTranslateY();
+ }
+
+ @LayoutlibDelegate
+ static void nSetTranslateY(long groupPtr, float translateY) {
+ VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
+ group.setTranslateY(translateY);
+ }
+
+ @LayoutlibDelegate
+ static void nSetPathData(long pathPtr, long pathDataPtr) {
+ VPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+ path.setPathData(PathParser_Delegate.getDelegate(pathDataPtr).getPathDataNodes());
+ }
+
+ @LayoutlibDelegate
+ static float nGetStrokeWidth(long pathPtr) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+ return path.getStrokeWidth();
+ }
+
+ @LayoutlibDelegate
+ static void nSetStrokeWidth(long pathPtr, float width) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+ path.setStrokeWidth(width);
+ }
+
+ @LayoutlibDelegate
+ static int nGetStrokeColor(long pathPtr) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+ return path.getStrokeColor();
+ }
+
+ @LayoutlibDelegate
+ static void nSetStrokeColor(long pathPtr, int strokeColor) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+ path.setStrokeColor(strokeColor);
+ }
+
+ @LayoutlibDelegate
+ static float nGetStrokeAlpha(long pathPtr) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+ return path.getStrokeAlpha();
+ }
+
+ @LayoutlibDelegate
+ static void nSetStrokeAlpha(long pathPtr, float alpha) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+ path.setStrokeAlpha(alpha);
+ }
+
+ @LayoutlibDelegate
+ static int nGetFillColor(long pathPtr) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+ return path.getFillColor();
+ }
+
+ @LayoutlibDelegate
+ static void nSetFillColor(long pathPtr, int fillColor) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+ path.setFillColor(fillColor);
+ }
+
+ @LayoutlibDelegate
+ static float nGetFillAlpha(long pathPtr) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+ return path.getFillAlpha();
+ }
+
+ @LayoutlibDelegate
+ static void nSetFillAlpha(long pathPtr, float fillAlpha) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+ path.setFillAlpha(fillAlpha);
+ }
+
+ @LayoutlibDelegate
+ static float nGetTrimPathStart(long pathPtr) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+ return path.getTrimPathStart();
+ }
+
+ @LayoutlibDelegate
+ static void nSetTrimPathStart(long pathPtr, float trimPathStart) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+ path.setTrimPathStart(trimPathStart);
+ }
+
+ @LayoutlibDelegate
+ static float nGetTrimPathEnd(long pathPtr) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+ return path.getTrimPathEnd();
+ }
+
+ @LayoutlibDelegate
+ static void nSetTrimPathEnd(long pathPtr, float trimPathEnd) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+ path.setTrimPathEnd(trimPathEnd);
+ }
+
+ @LayoutlibDelegate
+ static float nGetTrimPathOffset(long pathPtr) {
+ VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
+ return path.getTrimPathOffset();
+ }
+
+ @LayoutlibDelegate
+ static void nSetTrimPathOffset(long pathPtr, float trimPathOffset) {
+ VFullPath_Delegate path = VNativeObject.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>
+ */
+ interface VNativeObject {
+ @NonNull
+ static <T> T getDelegate(long nativePtr) {
+ //noinspection unchecked
+ T vNativeObject = (T) sPathManager.getDelegate(nativePtr);
+
+ assert vNativeObject != null;
+ return 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;
+ }
+ }
+
+ 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;
+
+ @NonNull
+ public Consumer<Float> getFloatPropertySetter(int propertyIdx) {
+ switch (propertyIdx) {
+ case STROKE_ALPHA_INDEX:
+ return this::setStrokeAlpha;
+ case FILL_ALPHA_INDEX:
+ return this::setFillAlpha;
+ case TRIM_PATH_START_INDEX:
+ return this::setTrimPathStart;
+ case TRIM_PATH_END_INDEX:
+ return this::setTrimPathEnd;
+ case TRIM_PATH_OFFSET_INDEX:
+ return this::setTrimPathOffset;
+ }
+
+ throw new IllegalArgumentException("Invalid VFullPath_Delegate property index "
+ + propertyIdx);
+ }
+
+ @NonNull
+ public Consumer<Integer> getIntPropertySetter(int propertyIdx) {
+ switch (propertyIdx) {
+ case STROKE_COLOR_INDEX:
+ return this::setStrokeColor;
+ case FILL_COLOR_INDEX:
+ return this::setFillColor;
+ }
+
+ throw new IllegalArgumentException("Invalid VFullPath_Delegate property index "
+ + propertyIdx);
+ }
+
+ /////////////////////////////////////////////////////
+ // Variables below need to be copied (deep copy if applicable) for mutation.
+
+ int mStrokeColor = Color.TRANSPARENT;
+ float mStrokeWidth = 0;
+
+ int mFillColor = Color.TRANSPARENT;
+ long mStrokeGradient = 0;
+ long mFillGradient = 0;
+ 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;
+
+ mStrokeGradient = copy.mStrokeGradient;
+ mFillGradient = copy.mFillGradient;
+ }
+
+ 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 void setStrokeGradient(long gradientPtr) {
+ mStrokeGradient = gradientPtr;
+ }
+
+ private void setFillGradient(long gradientPtr) {
+ mFillGradient = gradientPtr;
+ }
+ }
+
+ 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;
+
+ public Consumer<Float> getPropertySetter(int propertyIdx) {
+ switch (propertyIdx) {
+ case ROTATE_INDEX:
+ return this::setRotation;
+ case PIVOT_X_INDEX:
+ return this::setPivotX;
+ case PIVOT_Y_INDEX:
+ return this::setPivotY;
+ case SCALE_X_INDEX:
+ return this::setScaleX;
+ case SCALE_Y_INDEX:
+ return this::setScaleY;
+ case TRANSLATE_X_INDEX:
+ return this::setTranslateX;
+ case TRANSLATE_Y_INDEX:
+ return this::setTranslateY;
+ }
+
+ throw new IllegalArgumentException("Invalid VGroup_Delegate property index "
+ + propertyIdx);
+ }
+
+ /////////////////////////////////////////////////////
+ // 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);
+ }
+ }
+ }
+
+ 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;
+ }
+
+ 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);
+ fillPaintDelegate.setShader(fullPath.mFillGradient);
+ 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);
+ strokePaintDelegate.setShader(fullPath.mStrokeGradient);
+ 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/internal/view/animation/NativeInterpolatorFactoryHelper_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/view/animation/NativeInterpolatorFactoryHelper_Delegate.java
new file mode 100644
index 0000000..0f39e80
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/internal/view/animation/NativeInterpolatorFactoryHelper_Delegate.java
@@ -0,0 +1,128 @@
+/*
+ * 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.internal.view.animation;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.util.MathUtils;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AnticipateInterpolator;
+import android.view.animation.AnticipateOvershootInterpolator;
+import android.view.animation.BaseInterpolator;
+import android.view.animation.BounceInterpolator;
+import android.view.animation.CycleInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+import android.view.animation.OvershootInterpolator;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link
+ * NativeInterpolatorFactoryHelper}
+ * <p>
+ * Through the layoutlib_create tool, the original methods of NativeInterpolatorFactoryHelper have
+ * been replaced by calls to methods of the same name in this delegate class.
+ */
+@SuppressWarnings("unused")
+public class NativeInterpolatorFactoryHelper_Delegate {
+ private static final DelegateManager<Interpolator> sManager = new DelegateManager<>
+ (Interpolator.class);
+
+ public static Interpolator getDelegate(long nativePtr) {
+ return sManager.getDelegate(nativePtr);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long createAccelerateDecelerateInterpolator() {
+ return sManager.addNewDelegate(new AccelerateDecelerateInterpolator());
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long createAccelerateInterpolator(float factor) {
+ return sManager.addNewDelegate(new AccelerateInterpolator(factor));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long createAnticipateInterpolator(float tension) {
+ return sManager.addNewDelegate(new AnticipateInterpolator(tension));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long createAnticipateOvershootInterpolator(float tension) {
+ return sManager.addNewDelegate(new AnticipateOvershootInterpolator(tension));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long createBounceInterpolator() {
+ return sManager.addNewDelegate(new BounceInterpolator());
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long createCycleInterpolator(float cycles) {
+ return sManager.addNewDelegate(new CycleInterpolator(cycles));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long createDecelerateInterpolator(float factor) {
+ return sManager.addNewDelegate(new DecelerateInterpolator(factor));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long createLinearInterpolator() {
+ return sManager.addNewDelegate(new LinearInterpolator());
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long createOvershootInterpolator(float tension) {
+ return sManager.addNewDelegate(new OvershootInterpolator(tension));
+ }
+
+ private static class LutInterpolator extends BaseInterpolator {
+ private final float[] mValues;
+ private final int mSize;
+
+ private LutInterpolator(float[] values) {
+ mValues = values;
+ mSize = mValues.length;
+ }
+
+ @Override
+ public float getInterpolation(float input) {
+ float lutpos = input * mSize;
+ if (lutpos >= (mSize - 1)) {
+ return mValues[mSize - 1];
+ }
+
+ int ipart = (int) lutpos;
+ float weight = lutpos - ipart;
+
+ int i1 = ipart;
+ int i2 = Math.min(i1 + 1, mSize - 1);
+
+ assert i1 >= 0 && i2 >= 0 : "Negatives in the interpolation";
+
+ return MathUtils.lerp(mValues[i1], mValues[i2], weight);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long createLutInterpolator(float[] values) {
+ return sManager.addNewDelegate(new LutInterpolator(values));
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 17ab2ff5..c7ae6fc 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -52,11 +52,11 @@
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.BridgeAssetManager;
-import android.content.res.BridgeResources;
import android.content.res.BridgeTypedArray;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
+import android.content.res.Resources_Delegate;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
@@ -168,8 +168,8 @@
RTL_ATTRS.put("?android:attr/paddingRight", "paddingEnd");
RTL_ATTRS.put("?android:attr/layout_marginLeft", "layout_marginStart");
RTL_ATTRS.put("?android:attr/layout_marginRight", "layout_marginEnd");
- RTL_ATTRS.put("?android:attr/layout_toLeft", "layout_toStartOf");
- RTL_ATTRS.put("?android:attr/layout_toRight", "layout_toEndOf");
+ RTL_ATTRS.put("?android:attr/layout_toLeftOf", "layout_toStartOf");
+ RTL_ATTRS.put("?android:attr/layout_toRightOf", "layout_toEndOf");
RTL_ATTRS.put("?android:attr/layout_alignParentLeft", "layout_alignParentStart");
RTL_ATTRS.put("?android:attr/layout_alignParentRight", "layout_alignParentEnd");
RTL_ATTRS.put("?android:attr/drawableLeft", "drawableStart");
@@ -224,7 +224,7 @@
public void initResources() {
AssetManager assetManager = AssetManager.getSystem();
- mSystemResources = BridgeResources.initSystem(
+ mSystemResources = Resources_Delegate.initSystem(
this,
assetManager,
mMetrics,
@@ -237,7 +237,7 @@
* Disposes the {@link Resources} singleton.
*/
public void disposeResources() {
- BridgeResources.disposeSystem();
+ Resources_Delegate.disposeSystem();
}
public void setBridgeInflater(BridgeInflater inflater) {
@@ -706,8 +706,8 @@
List<Pair<String, Boolean>> attributeList = searchAttrs(attrs);
- BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
- isPlatformFile);
+ BridgeTypedArray ta =
+ Resources_Delegate.newTypeArray(mSystemResources, attrs.length, isPlatformFile);
// look for a custom style.
String customStyle = null;
@@ -941,7 +941,7 @@
List<Pair<String, Boolean>> attributes = searchAttrs(attrs);
- BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
+ BridgeTypedArray ta = Resources_Delegate.newTypeArray(mSystemResources, attrs.length,
false);
// for each attribute, get its name so that we can search it in the style
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/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index c72eeb1..494b3d2 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -33,7 +33,11 @@
import org.xmlpull.v1.XmlPullParserException;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.res.ColorStateList;
+import android.content.res.ComplexColor;
+import android.content.res.ComplexColor_Accessor;
+import android.content.res.GradientColor;
import android.content.res.Resources.Theme;
import android.graphics.Bitmap;
import android.graphics.Bitmap_Delegate;
@@ -47,6 +51,7 @@
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
@@ -119,54 +124,128 @@
throw new NumberFormatException();
}
- public static ColorStateList getColorStateList(ResourceValue resValue, BridgeContext context) {
+ /**
+ * Returns a {@link ComplexColor} from the given {@link ResourceValue}
+ *
+ * @param resValue the value containing a color value or a file path to a complex color
+ * definition
+ * @param context the current context
+ * @param theme the theme to use when resolving the complex color
+ * @param allowGradients when false, only {@link ColorStateList} will be returned. If a {@link
+ * GradientColor} is found, null will be returned.
+ */
+ @Nullable
+ private static ComplexColor getInternalComplexColor(@NonNull ResourceValue resValue,
+ @NonNull BridgeContext context, @Nullable Theme theme, boolean allowGradients) {
String value = resValue.getValue();
- if (value != null && !RenderResources.REFERENCE_NULL.equals(value)) {
- // first check if the value is a file (xml most likely)
+ if (value == null || RenderResources.REFERENCE_NULL.equals(value)) {
+ return null;
+ }
+
+ // first check if the value is a file (xml most likely)
+ XmlPullParser parser = context.getLayoutlibCallback().getXmlFileParser(value);
+ if (parser == null) {
File f = new File(value);
if (f.isFile()) {
+ // let the framework inflate the color from the XML file, by
+ // providing an XmlPullParser
try {
- // let the framework inflate the ColorStateList from the XML file, by
- // providing an XmlPullParser
- XmlPullParser parser = ParserFactory.create(f);
-
- BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
- parser, context, resValue.isFramework());
- try {
- return ColorStateList.createFromXml(context.getResources(), blockParser);
- } finally {
- blockParser.ensurePopped();
- }
- } catch (XmlPullParserException e) {
- Bridge.getLog().error(LayoutLog.TAG_BROKEN,
- "Failed to configure parser for " + value, e, null /*data*/);
- // we'll return null below.
- } catch (Exception e) {
- // this is an error and not warning since the file existence is
- // checked before attempting to parse it.
+ parser = ParserFactory.create(f);
+ } catch (XmlPullParserException | FileNotFoundException e) {
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
"Failed to parse file " + value, e, null /*data*/);
-
- return null;
- }
- } else {
- // try to load the color state list from an int
- try {
- int color = ResourceHelper.getColor(value);
- return ColorStateList.valueOf(color);
- } catch (NumberFormatException e) {
- Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
- "Failed to convert " + value + " into a ColorStateList", e,
- null /*data*/);
- return null;
}
}
}
+ if (parser != null) {
+ try {
+ BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
+ parser, context, resValue.isFramework());
+ try {
+ // Advance the parser to the first element so we can detect if it's a
+ // color list or a gradient color
+ int type;
+ //noinspection StatementWithEmptyBody
+ while ((type = blockParser.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 = blockParser.getName();
+ if (allowGradients && "gradient".equals(name)) {
+ return ComplexColor_Accessor.createGradientColorFromXmlInner(
+ context.getResources(),
+ blockParser, blockParser,
+ theme);
+ } else if ("selector".equals(name)) {
+ return ComplexColor_Accessor.createColorStateListFromXmlInner(
+ context.getResources(),
+ blockParser, blockParser,
+ theme);
+ }
+ } finally {
+ blockParser.ensurePopped();
+ }
+ } catch (XmlPullParserException e) {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ "Failed to configure parser for " + value, e, null /*data*/);
+ // we'll return null below.
+ } catch (Exception e) {
+ // this is an error and not warning since the file existence is
+ // checked before attempting to parse it.
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
+ "Failed to parse file " + value, e, null /*data*/);
+
+ return null;
+ }
+ } else {
+ // try to load the color state list from an int
+ try {
+ int color = getColor(value);
+ return ColorStateList.valueOf(color);
+ } catch (NumberFormatException e) {
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
+ "Failed to convert " + value + " into a ColorStateList", e,
+ null /*data*/);
+ }
+ }
+
return null;
}
/**
+ * Returns a {@link ColorStateList} from the given {@link ResourceValue}
+ *
+ * @param resValue the value containing a color value or a file path to a complex color
+ * definition
+ * @param context the current context
+ */
+ @Nullable
+ public static ColorStateList getColorStateList(@NonNull ResourceValue resValue,
+ @NonNull BridgeContext context) {
+ return (ColorStateList) getInternalComplexColor(resValue, context, context.getTheme(),
+ false);
+ }
+
+ /**
+ * Returns a {@link ComplexColor} from the given {@link ResourceValue}
+ *
+ * @param resValue the value containing a color value or a file path to a complex color
+ * definition
+ * @param context the current context
+ */
+ @Nullable
+ public static ComplexColor getComplexColor(@NonNull ResourceValue resValue,
+ @NonNull BridgeContext context) {
+ return getInternalComplexColor(resValue, context, context.getTheme(), true);
+ }
+
+ /**
* Returns a drawable from the given value.
* @param value The value that contains a path to a 9 patch, a bitmap or a xml based drawable,
* or an hexadecimal color
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/NinePatchInputStream.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/NinePatchInputStream.java
new file mode 100644
index 0000000..96b795a
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/NinePatchInputStream.java
@@ -0,0 +1,50 @@
+/*
+ * 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.layoutlib.bridge.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+
+/**
+ * Simpler wrapper around FileInputStream. This is used when the input stream represent
+ * not a normal bitmap but a nine patch.
+ * This is useful when the InputStream is created in a method but used in another that needs
+ * to know whether this is 9-patch or not, such as BitmapFactory.
+ */
+public class NinePatchInputStream extends FileInputStream {
+ private boolean mFakeMarkSupport = true;
+ public NinePatchInputStream(File file) throws FileNotFoundException {
+ super(file);
+ }
+
+ @Override
+ public boolean markSupported() {
+ if (mFakeMarkSupport) {
+ // this is needed so that BitmapFactory doesn't wrap this in a BufferedInputStream.
+ return true;
+ }
+
+ return super.markSupported();
+ }
+
+ public void disableFakeMarkSupport() {
+ // disable fake mark support so that in case codec actually try to use them
+ // we don't lie to them.
+ mFakeMarkSupport = false;
+ }
+}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
index 72b87ab..47cb042 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/color/gradient.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/color/gradient.xml
new file mode 100644
index 0000000..fc0afa6
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/color/gradient.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:startX="10"
+ android:startY="10"
+ android:endX="50"
+ android:endY="50"
+ android:startColor="#ffff0000"
+ android:endColor="#ff00ff00" />
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/multi_path.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/multi_path.xml
index ffc70dc..5c19b08 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/multi_path.xml
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/multi_path.xml
@@ -53,6 +53,16 @@
android:trimPathStart="0.2"
android:trimPathEnd="0.8"
/>
+
+ <!--
+ Draw a line with gradient stroke color
+ -->
+ <path
+ android:strokeWidth="1"
+ android:strokeColor="#FF00FF"
+ android:fillColor="@color/gradient"
+ android:pathData="M-20,-20 l0, 10 l10, 0 l0, -10 l-10,0 "
+ />
</group>
</vector>
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index 6b23da7..2726042 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -335,7 +335,7 @@
.setNavigation(Navigation.NONAV);
SessionParams params = getSessionParams(parser, customConfigGenerator,
- layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", false,
+ layoutLibCallback, "Theme.Material.Light.NoActionBar.Fullscreen", false,
RenderingMode.V_SCROLL, 22);
renderAndVerify(params, "expand_vert_layout.png");
@@ -348,7 +348,7 @@
parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
"expand_horz_layout.xml");
params = getSessionParams(parser, customConfigGenerator,
- layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", false,
+ layoutLibCallback, "Theme.Material.Light.NoActionBar.Fullscreen", false,
RenderingMode.H_SCROLL, 22);
renderAndVerify(params, "expand_horz_layout.png");
diff --git a/tools/layoutlib/create/create.iml b/tools/layoutlib/create/create.iml
index b2b14b4..368b46b 100644
--- a/tools/layoutlib/create/create.iml
+++ b/tools/layoutlib/create/create.iml
@@ -22,6 +22,6 @@
</SOURCES>
</library>
</orderEntry>
- <orderEntry type="library" scope="TEST" name="JUnit4" level="application" />
+ <orderEntry type="library" scope="TEST" name="junit" level="project" />
</component>
</module>
\ No newline at end of file
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index 5b99a6b..3b37612 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -367,6 +367,10 @@
ClassVisitor cv = cw;
+ // FIXME Generify
+ if ("android/content/res/Resources".equals(className)) {
+ cv = new FieldInjectorAdapter(cv);
+ }
if (mReplaceMethodCallsClasses.contains(className)) {
cv = new ReplaceMethodCallsAdapter(cv, className);
}
@@ -445,4 +449,5 @@
}
return buffer.toByteArray();
}
+
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 8a23e4b..bd37665 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
@@ -155,6 +155,31 @@
*/
public final static String[] DELEGATE_METHODS = new String[] {
"android.app.Fragment#instantiate", //(Landroid/content/Context;Ljava/lang/String;Landroid/os/Bundle;)Landroid/app/Fragment;",
+ "android.content.res.Resources#getAnimation",
+ "android.content.res.Resources#getBoolean",
+ "android.content.res.Resources#getColor",
+ "android.content.res.Resources#getColorStateList",
+ "android.content.res.Resources#getDimension",
+ "android.content.res.Resources#getDimensionPixelOffset",
+ "android.content.res.Resources#getDimensionPixelSize",
+ "android.content.res.Resources#getDrawable",
+ "android.content.res.Resources#getIntArray",
+ "android.content.res.Resources#getInteger",
+ "android.content.res.Resources#getLayout",
+ "android.content.res.Resources#getResourceEntryName",
+ "android.content.res.Resources#getResourceName",
+ "android.content.res.Resources#getResourceTypeName",
+ "android.content.res.Resources#getString",
+ "android.content.res.Resources#getStringArray",
+ "android.content.res.Resources#getText",
+ "android.content.res.Resources#getTextArray",
+ "android.content.res.Resources#getValue",
+ "android.content.res.Resources#getXml",
+ "android.content.res.Resources#loadXmlResourceParser",
+ "android.content.res.Resources#obtainAttributes",
+ "android.content.res.Resources#obtainTypedArray",
+ "android.content.res.Resources#openRawResource",
+ "android.content.res.Resources#openRawResourceFd",
"android.content.res.Resources$Theme#obtainStyledAttributes",
"android.content.res.Resources$Theme#resolveAttribute",
"android.content.res.Resources$Theme#resolveAttributes",
@@ -164,6 +189,7 @@
"android.content.res.TypedArray#obtain",
"android.graphics.BitmapFactory#finishDecode",
"android.graphics.BitmapFactory#setDensityFromOptions",
+ "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT#useLastSeenTarget",
"android.graphics.drawable.GradientDrawable#buildRing",
"android.graphics.Typeface#getSystemFontConfigLocation",
"android.graphics.Typeface#makeFamilyFromParsed",
@@ -269,12 +295,15 @@
"android.graphics.SweepGradient",
"android.graphics.Typeface",
"android.graphics.Xfermode",
+ "android.graphics.drawable.AnimatedVectorDrawable",
+ "android.graphics.drawable.VectorDrawable",
"android.os.SystemClock",
"android.os.SystemProperties",
"android.text.AndroidBidi",
"android.text.StaticLayout",
"android.util.PathParser",
"android.view.Display",
+ "com.android.internal.view.animation.NativeInterpolatorFactoryHelper",
"libcore.icu.ICU",
};
@@ -312,7 +341,7 @@
// Use android.icu.text versions of DateFormat and SimpleDateFormat since the
// original ones do not match the Android implementation
"java.text.DateFormat", "android.icu.text.DateFormat",
- "java.text.SimpleDateFormat", "android.icu.text.SimpleDateFormat"
+ "java.text.SimpleDateFormat", "android.icu.text.SimpleDateFormat",
};
private final static String[] EXCLUDED_CLASSES =
@@ -321,7 +350,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/tools/layoutlib/create/src/com/android/tools/layoutlib/create/FieldInjectorAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/FieldInjectorAdapter.java
new file mode 100644
index 0000000..4608a84
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/FieldInjectorAdapter.java
@@ -0,0 +1,40 @@
+/*
+ * 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.tools.layoutlib.create;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Injects fields in a class.
+ * <p>
+ * TODO: Generify
+ */
+public class FieldInjectorAdapter extends ClassVisitor {
+ public FieldInjectorAdapter(ClassVisitor cv) {
+ super(Opcodes.ASM4, cv);
+ }
+
+ @Override
+ public void visitEnd() {
+ super.visitField(Opcodes.ACC_PUBLIC, "mLayoutlibCallback",
+ "Lcom/android/ide/common/rendering/api/LayoutlibCallback;", null, null);
+ super.visitField(Opcodes.ACC_PUBLIC, "mContext",
+ "Lcom/android/layoutlib/bridge/android/BridgeContext;", null, null);
+ super.visitEnd();
+ }
+}
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
index 0912fb1..afaa399 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
@@ -53,12 +53,10 @@
private MockLog mLog;
- private static final String NATIVE_CLASS_NAME = ClassWithNative.class.getCanonicalName();
- private static final String OUTER_CLASS_NAME = OuterClass.class.getCanonicalName();
- private static final String INNER_CLASS_NAME = OuterClass.class.getCanonicalName() + "$" +
- InnerClass.class.getSimpleName();
- private static final String STATIC_INNER_CLASS_NAME =
- OuterClass.class.getCanonicalName() + "$" + StaticInnerClass.class.getSimpleName();
+ private static final String NATIVE_CLASS_NAME = ClassWithNative.class.getName();
+ private static final String OUTER_CLASS_NAME = OuterClass.class.getName();
+ private static final String INNER_CLASS_NAME = InnerClass.class.getName();
+ private static final String STATIC_INNER_CLASS_NAME = StaticInnerClass.class.getName();
@Before
public void setUp() throws Exception {
@@ -69,12 +67,12 @@
/**
* Tests that a class not being modified still works.
*/
- @SuppressWarnings("unchecked")
@Test
public void testNoOp() throws Throwable {
// create an instance of the class that will be modified
// (load the class in a distinct class loader so that we can trash its definition later)
ClassLoader cl1 = new ClassLoader(this.getClass().getClassLoader()) { };
+ @SuppressWarnings("unchecked")
Class<ClassWithNative> clazz1 = (Class<ClassWithNative>) cl1.loadClass(NATIVE_CLASS_NAME);
ClassWithNative instance1 = clazz1.newInstance();
assertEquals(42, instance1.add(20, 22));
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/StubMethodAdapterTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/StubMethodAdapterTest.java
new file mode 100644
index 0000000..3db3e23
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/StubMethodAdapterTest.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.tools.layoutlib.create;
+
+import com.android.tools.layoutlib.create.dataclass.StubClass;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import java.lang.reflect.Method;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+
+import static org.junit.Assert.*;
+
+public class StubMethodAdapterTest {
+
+ private static final String STUB_CLASS_NAME = StubClass.class.getName();
+
+ /**
+ * Load a dummy class, stub one of its method and ensure that the modified class works as
+ * intended.
+ */
+ @Test
+ public void testBoolean() throws Exception {
+ final String methodName = "returnTrue";
+ // First don't change the method and assert that it returns true
+ testBoolean((name, type) -> false, Assert::assertTrue, methodName);
+ // Change the method now and assert that it returns false.
+ testBoolean((name, type) -> methodName.equals(name) &&
+ Type.BOOLEAN_TYPE.equals(type.getReturnType()), Assert::assertFalse, methodName);
+ }
+
+ /**
+ * @param methodPredicate tests if the method should be replaced
+ */
+ private void testBoolean(BiPredicate<String, Type> methodPredicate, Consumer<Boolean> assertion,
+ String methodName) throws Exception {
+ ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+ // Always rename the class to avoid conflict with the original class.
+ String newClassName = STUB_CLASS_NAME + '_';
+ new ClassReader(STUB_CLASS_NAME).accept(
+ new ClassAdapter(newClassName, writer, methodPredicate), 0);
+ MyClassLoader myClassLoader = new MyClassLoader(newClassName, writer.toByteArray());
+ Class<?> aClass = myClassLoader.loadClass(newClassName);
+ assertTrue("StubClass not loaded by the classloader. Likely a bug in the test.",
+ myClassLoader.findClassCalled);
+ Method method = aClass.getMethod(methodName);
+ Object o = aClass.newInstance();
+ assertion.accept((Boolean) method.invoke(o));
+ }
+
+ private static class ClassAdapter extends ClassVisitor {
+
+ private final String mClassName;
+ private final BiPredicate<String, Type> mMethodPredicate;
+
+ private ClassAdapter(String className, ClassVisitor cv,
+ BiPredicate<String, Type> methodPredicate) {
+ super(Main.ASM_VERSION, cv);
+ mClassName = className.replace('.', '/');
+ mMethodPredicate = methodPredicate;
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName,
+ String[] interfaces) {
+ super.visit(version, access, mClassName, signature, superName,
+ interfaces);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+ String[] exceptions) {
+ // Copied partly from
+ // com.android.tools.layoutlib.create.DelegateClassAdapter.visitMethod()
+ // but not generating the _Original method.
+ boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
+ boolean isNative = (access & Opcodes.ACC_NATIVE) != 0;
+ MethodVisitor originalMethod =
+ super.visitMethod(access, name, desc, signature, exceptions);
+ Type descriptor = Type.getMethodType(desc);
+ if (mMethodPredicate.test(name, descriptor)) {
+ String methodSignature = mClassName + "#" + name;
+ String invokeSignature = methodSignature + desc;
+ return new StubMethodAdapter(originalMethod, name, descriptor.getReturnType(),
+ invokeSignature, isStatic, isNative);
+ }
+ return originalMethod;
+ }
+ }
+
+ private static class MyClassLoader extends ClassLoader {
+ private final String mName;
+ private final byte[] mBytes;
+ private boolean findClassCalled;
+
+ private MyClassLoader(String name, byte[] bytes) {
+ mName = name;
+ mBytes = bytes;
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ if (name.equals(mName)) {
+ findClassCalled = true;
+ return defineClass(name, mBytes, 0, mBytes.length);
+ }
+ return super.findClass(name);
+ }
+ }
+}
diff --git a/core/java/android/hardware/ICameraServiceListener.aidl b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/StubClass.java
similarity index 62%
rename from core/java/android/hardware/ICameraServiceListener.aidl
rename to tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/StubClass.java
index 49278b6..3ae8e47 100644
--- a/core/java/android/hardware/ICameraServiceListener.aidl
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/StubClass.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 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,15 +14,17 @@
* limitations under the License.
*/
-package android.hardware;
+package com.android.tools.layoutlib.create.dataclass;
-/** @hide */
-interface ICameraServiceListener
-{
- /**
- * Keep up-to-date with frameworks/av/include/camera/ICameraServiceListener.h
- */
- void onStatusChanged(int status, int cameraId);
+import com.android.tools.layoutlib.create.StubMethodAdapterTest;
- void onTorchStatusChanged(int status, String cameraId);
+/**
+ * Used by {@link StubMethodAdapterTest}
+ */
+@SuppressWarnings("unused")
+public class StubClass {
+
+ public boolean returnTrue() {
+ return true;
+ }
}
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index 59416b8..13abaff 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -300,7 +300,7 @@
try {
mRttCapabilities = mService.getRttCapabilities();
} catch (RemoteException e) {
- Log.e(TAG, "Can not get RTT Capabilities");
+ throw e.rethrowFromSystemServer();
}
}
return mRttCapabilities;
@@ -1132,7 +1132,7 @@
Log.d(TAG, "Get the messenger from " + mService);
messenger = mService.getMessenger();
} catch (RemoteException e) {
- /* do nothing */
+ throw e.rethrowFromSystemServer();
} catch (SecurityException e) {
/* do nothing */
}
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index a46aaec..a9259fa 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -305,9 +305,12 @@
*/
public static class InformationElement {
public static final int EID_SSID = 0;
+ public static final int EID_SUPPORTED_RATES = 1;
public static final int EID_TIM = 5;
public static final int EID_BSS_LOAD = 11;
+ public static final int EID_ERP = 42;
public static final int EID_RSN = 48;
+ public static final int EID_EXTENDED_SUPPORTED_RATES = 50;
public static final int EID_HT_OPERATION = 61;
public static final int EID_INTERWORKING = 107;
public static final int EID_ROAMING_CONSORTIUM = 111;
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 4921073..a5bfd3c 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -39,9 +39,9 @@
import android.util.Log;
import android.util.SparseArray;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
+import com.android.server.net.NetworkPinner;
import java.net.InetAddress;
import java.util.ArrayList;
@@ -678,11 +678,6 @@
private static int sThreadRefCount;
private static HandlerThread sHandlerThread;
- @GuardedBy("sCM")
- // TODO: Introduce refcounting and make this a per-process static callback, instead of a
- // per-WifiManager callback.
- private PinningNetworkCallback mNetworkCallback;
-
/**
* Create a new WifiManager instance.
* Applications will almost always want to use
@@ -723,8 +718,7 @@
try {
return mService.getConfiguredNetworks();
} catch (RemoteException e) {
- Log.w(TAG, "Caught RemoteException trying to get configured networks: " + e);
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -734,7 +728,7 @@
try {
return mService.getPrivilegedConfiguredNetworks();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -744,7 +738,7 @@
try {
return mService.getConnectionStatistics();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -758,7 +752,7 @@
try {
return mService.getMatchingWifiConfig(scanResult);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -818,7 +812,7 @@
try {
return mService.addOrUpdateNetwork(config);
} catch (RemoteException e) {
- return -1;
+ throw e.rethrowFromSystemServer();
}
}
@@ -832,7 +826,7 @@
try {
return mService.addPasspointManagementObject(mo);
} catch (RemoteException e) {
- return -1;
+ throw e.rethrowFromSystemServer();
}
}
@@ -848,7 +842,7 @@
try {
return mService.modifyPasspointManagementObject(fqdn, mos);
} catch (RemoteException e) {
- return -1;
+ throw e.rethrowFromSystemServer();
}
}
@@ -862,6 +856,7 @@
try {
mService.queryPasspointIcon(bssid, fileName);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -875,7 +870,7 @@
try {
return mService.matchProviderWithCurrentNetwork(fqdn);
} catch (RemoteException e) {
- return -1;
+ throw e.rethrowFromSystemServer();
}
}
@@ -889,28 +884,11 @@
try {
mService.deauthenticateNetwork(holdoff, ess);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
/**
- * 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.
@@ -922,7 +900,7 @@
try {
return mService.removeNetwork(netId);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -955,18 +933,22 @@
public boolean enableNetwork(int netId, boolean disableOthers) {
final boolean pin = disableOthers && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
if (pin) {
- registerPinningNetworkCallback();
+ NetworkRequest request = new NetworkRequest.Builder()
+ .clearCapabilities()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .build();
+ NetworkPinner.pin(mContext, request);
}
boolean success;
try {
success = mService.enableNetwork(netId, disableOthers);
} catch (RemoteException e) {
- success = false;
+ throw e.rethrowFromSystemServer();
}
if (pin && !success) {
- unregisterPinningNetworkCallback();
+ NetworkPinner.unpin();
}
return success;
@@ -983,7 +965,7 @@
try {
return mService.disableNetwork(netId);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -997,7 +979,7 @@
mService.disconnect();
return true;
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1012,7 +994,7 @@
mService.reconnect();
return true;
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1027,7 +1009,7 @@
mService.reassociate();
return true;
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1042,7 +1024,7 @@
try {
return mService.pingSupplicant();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1090,7 +1072,7 @@
try {
return mService.getSupportedFeatures();
} catch (RemoteException e) {
- return 0;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1216,9 +1198,8 @@
return mService.reportActivityInfo();
}
} catch (RemoteException e) {
- Log.e(TAG, "getControllerActivityEnergyInfo: " + e);
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -1232,7 +1213,7 @@
mService.startScan(null, null);
return true;
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1243,7 +1224,7 @@
mService.startScan(null, workSource);
return true;
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1299,7 +1280,7 @@
try {
return mService.getWpsNfcConfigurationToken(netId);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1311,7 +1292,7 @@
try {
return mService.getConnectionInfo();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1328,7 +1309,7 @@
try {
return mService.getScanResults(mContext.getOpPackageName());
} catch (RemoteException e) {
- return new ArrayList<ScanResult>();
+ throw e.rethrowFromSystemServer();
}
}
@@ -1344,7 +1325,7 @@
try {
return mService.isScanAlwaysAvailable();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1361,7 +1342,7 @@
try {
return mService.saveConfiguration();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1375,7 +1356,9 @@
public void setCountryCode(String country, boolean persist) {
try {
mService.setCountryCode(country, persist);
- } catch (RemoteException e) { }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -1387,9 +1370,9 @@
public String getCountryCode() {
try {
String country = mService.getCountryCode();
- return(country);
+ return country;
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1405,7 +1388,9 @@
public void setFrequencyBand(int band, boolean persist) {
try {
mService.setFrequencyBand(band, persist);
- } catch (RemoteException e) { }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -1421,7 +1406,7 @@
try {
return mService.getFrequencyBand();
} catch (RemoteException e) {
- return -1;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1434,7 +1419,7 @@
try {
return mService.isDualBandSupported();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1447,7 +1432,7 @@
try {
return mService.getDhcpInfo();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1461,7 +1446,7 @@
try {
return mService.setWifiEnabled(enabled);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1476,7 +1461,7 @@
try {
return mService.getWifiEnabledState();
} catch (RemoteException e) {
- return WIFI_STATE_UNKNOWN;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1553,7 +1538,7 @@
mService.setWifiApEnabled(wifiConfig, enabled);
return true;
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1571,7 +1556,7 @@
try {
return mService.getWifiApEnabledState();
} catch (RemoteException e) {
- return WIFI_AP_STATE_FAILED;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1598,7 +1583,7 @@
try {
return mService.getWifiApConfiguration();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1612,8 +1597,7 @@
try {
return mService.buildWifiConfig(uriString, mimeType, data);
} catch (RemoteException e) {
- Log.w(TAG, "Caught RemoteException trying to build wifi config: " + e);
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1629,7 +1613,7 @@
mService.setWifiApConfiguration(wifiConfig);
return true;
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1646,7 +1630,7 @@
mService.addToBlacklist(bssid);
return true;
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1663,7 +1647,7 @@
mService.clearBlacklist();
return true;
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1692,7 +1676,7 @@
try {
mService.enableTdls(remoteIPAddress.getHostAddress(), enable);
} catch (RemoteException e) {
- // Just ignore the exception
+ throw e.rethrowFromSystemServer();
}
}
@@ -1706,7 +1690,7 @@
try {
mService.enableTdlsWithMacAddress(remoteMacAddress, enable);
} catch (RemoteException e) {
- // Just ignore the exception
+ throw e.rethrowFromSystemServer();
}
}
@@ -2012,100 +1996,6 @@
"No permission to access and change wifi or a bad initialization");
}
- private void initConnectivityManager() {
- // TODO: what happens if an app calls a WifiManager API before ConnectivityManager is
- // registered? Can we fix this by starting ConnectivityService before WifiService?
- if (sCM == null) {
- sCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- if (sCM == null) {
- throw new IllegalStateException("Bad luck, ConnectivityService not started.");
- }
- }
- }
-
- /**
- * A NetworkCallback that pins the process to the first wifi network to connect.
- *
- * We use this to maintain compatibility with pre-M apps that call WifiManager.enableNetwork()
- * to connect to a Wi-Fi network that has no Internet access, and then assume that they will be
- * able to use that network because it's the system default.
- *
- * In order to maintain compatibility with apps that call setProcessDefaultNetwork themselves,
- * we try not to set the default network unless they have already done so, and we try not to
- * clear the default network unless we set it ourselves.
- *
- * This should maintain behaviour that's compatible with L, which would pin the whole system to
- * any wifi network that was created via enableNetwork(..., true) until that network
- * disconnected.
- *
- * Note that while this hack allows network traffic to flow, it is quite limited. For example:
- *
- * 1. setProcessDefaultNetwork only affects this process, so:
- * - Any subprocesses spawned by this process will not be pinned to Wi-Fi.
- * - If this app relies on any other apps on the device also being on Wi-Fi, that won't work
- * either, because other apps on the device will not be pinned.
- * 2. The behaviour of other APIs is not modified. For example:
- * - getActiveNetworkInfo will return the system default network, not Wi-Fi.
- * - There will be no CONNECTIVITY_ACTION broadcasts about TYPE_WIFI.
- * - getProcessDefaultNetwork will not return null, so if any apps are relying on that, they
- * will be surprised as well.
- */
- private class PinningNetworkCallback extends NetworkCallback {
- private Network mPinnedNetwork;
-
- @Override
- public void onPreCheck(Network network) {
- if (sCM.getProcessDefaultNetwork() == null && mPinnedNetwork == null) {
- sCM.setProcessDefaultNetwork(network);
- mPinnedNetwork = network;
- Log.d(TAG, "Wifi alternate reality enabled on network " + network);
- }
- }
-
- @Override
- public void onLost(Network network) {
- if (network.equals(mPinnedNetwork) && network.equals(sCM.getProcessDefaultNetwork())) {
- sCM.setProcessDefaultNetwork(null);
- Log.d(TAG, "Wifi alternate reality disabled on network " + network);
- mPinnedNetwork = null;
- unregisterPinningNetworkCallback();
- }
- }
- }
-
- private void registerPinningNetworkCallback() {
- initConnectivityManager();
- synchronized (sCM) {
- if (mNetworkCallback == null) {
- // TODO: clear all capabilities.
- NetworkRequest request = new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .build();
- mNetworkCallback = new PinningNetworkCallback();
- try {
- sCM.registerNetworkCallback(request, mNetworkCallback);
- } catch (SecurityException e) {
- Log.d(TAG, "Failed to register network callback", e);
- }
- }
- }
- }
-
- private void unregisterPinningNetworkCallback() {
- initConnectivityManager();
- synchronized (sCM) {
- if (mNetworkCallback != null) {
- try {
- sCM.unregisterNetworkCallback(mNetworkCallback);
- } catch (SecurityException e) {
- Log.d(TAG, "Failed to unregister network callback", e);
- }
- mNetworkCallback = null;
- }
- }
- }
-
/**
* Connect to a network with the given configuration. The network also
* gets added to the supplicant configuration.
@@ -2219,6 +2109,7 @@
try {
mService.disableEphemeralNetwork(SSID);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2259,7 +2150,7 @@
try {
return mService.getWifiServiceMessenger();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
} catch (SecurityException e) {
return null;
}
@@ -2274,7 +2165,7 @@
try {
return mService.getConfigFile();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2340,7 +2231,8 @@
}
mActiveLockCount++;
}
- } catch (RemoteException ignore) {
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
mHeld = true;
}
@@ -2367,7 +2259,8 @@
synchronized (WifiManager.this) {
mActiveLockCount--;
}
- } catch (RemoteException ignore) {
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
mHeld = false;
}
@@ -2427,6 +2320,7 @@
try {
mService.updateWifiLockWorkSource(mBinder, mWorkSource);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2456,7 +2350,8 @@
synchronized (WifiManager.this) {
mActiveLockCount--;
}
- } catch (RemoteException ignore) {
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -2572,7 +2467,8 @@
}
mActiveLockCount++;
}
- } catch (RemoteException ignore) {
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
mHeld = true;
}
@@ -2611,7 +2507,8 @@
synchronized (WifiManager.this) {
mActiveLockCount--;
}
- } catch (RemoteException ignore) {
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
mHeld = false;
}
@@ -2685,7 +2582,7 @@
try {
return mService.isMulticastEnabled();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2698,7 +2595,7 @@
mService.initializeMulticastFiltering();
return true;
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2736,7 +2633,7 @@
try {
return mService.getVerboseLoggingLevel();
} catch (RemoteException e) {
- return 0;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2748,7 +2645,7 @@
try {
mService.enableAggressiveHandover(enabled);
} catch (RemoteException e) {
-
+ throw e.rethrowFromSystemServer();
}
}
@@ -2761,7 +2658,7 @@
try {
return mService.getAggressiveHandover();
} catch (RemoteException e) {
- return 0;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2773,7 +2670,7 @@
try {
mService.setAllowScansWithTraffic(enabled);
} catch (RemoteException e) {
-
+ throw e.rethrowFromSystemServer();
}
}
@@ -2785,7 +2682,7 @@
try {
return mService.getAllowScansWithTraffic();
} catch (RemoteException e) {
- return 0;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2798,6 +2695,7 @@
try {
mService.factoryReset();
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2810,7 +2708,7 @@
try {
return mService.getCurrentNetwork();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2824,7 +2722,7 @@
try {
return mService.enableAutoJoinWhenAssociated(enabled);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2836,7 +2734,7 @@
try {
return mService.getEnableAutoJoinWhenAssociated();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
/**
@@ -2847,7 +2745,7 @@
try {
mService.setHalBasedAutojoinOffload(enabled);
} catch (RemoteException e) {
-
+ throw e.rethrowFromSystemServer();
}
}
@@ -2859,7 +2757,7 @@
try {
return mService.getHalBasedAutojoinOffload();
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return 0;
}
}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 69e179d..c5e7bff 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -169,6 +169,13 @@
public int band;
/** list of channels; used when band is set to WIFI_BAND_UNSPECIFIED */
public ChannelSpec[] channels;
+ /**
+ * list of networkId's of hidden networks to scan for.
+ * These Id's should correspond to the wpa_supplicant's networkId's and will be used
+ * in connectivity scans using wpa_supplicant.
+ * {@hide}
+ * */
+ public int[] hiddenNetworkIds;
/** period of background scan; in millisecond, 0 => single shot scan */
public int periodInMs;
/** must have a valid REPORT_EVENT value */
@@ -192,6 +199,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,10 +219,9 @@
dest.writeInt(maxScansToCache);
dest.writeInt(maxPeriodInMs);
dest.writeInt(stepCount);
-
+ dest.writeInt(isPnoScan ? 1 : 0);
if (channels != null) {
dest.writeInt(channels.length);
-
for (int i = 0; i < channels.length; i++) {
dest.writeInt(channels[i].frequency);
dest.writeInt(channels[i].dwellTimeMS);
@@ -219,13 +230,13 @@
} else {
dest.writeInt(0);
}
+ dest.writeIntArray(hiddenNetworkIds);
}
/** Implement the Parcelable interface {@hide} */
public static final Creator<ScanSettings> CREATOR =
new Creator<ScanSettings>() {
public ScanSettings createFromParcel(Parcel in) {
-
ScanSettings settings = new ScanSettings();
settings.band = in.readInt();
settings.periodInMs = in.readInt();
@@ -234,17 +245,17 @@
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++) {
int frequency = in.readInt();
-
ChannelSpec spec = new ChannelSpec(frequency);
spec.dwellTimeMS = in.readInt();
spec.passive = in.readInt() == 1;
settings.channels[i] = spec;
}
-
+ settings.hiddenNetworkIds = in.createIntArray();
return settings;
}
@@ -436,6 +447,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 +619,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 +696,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 +1068,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 +1360,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;
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java
index 667c4b1..1b78beb 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -75,7 +75,7 @@
}
mService.connect(mBinder, listener.callback, events);
} catch (RemoteException e) {
- Log.w(TAG, "connect RemoteException (FYI - ignoring): " + e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -94,7 +94,7 @@
mService.disconnect(mBinder);
mBinder = null;
} catch (RemoteException e) {
- Log.w(TAG, "disconnect RemoteException (FYI - ignoring): " + e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -116,7 +116,7 @@
try {
mService.requestConfig(configRequest);
} catch (RemoteException e) {
- Log.w(TAG, "requestConfig RemoteException (FYI - ignoring): " + e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -173,8 +173,7 @@
if (DBG) Log.d(TAG, "publish: session created - sessionId=" + sessionId);
mService.publish(sessionId, publishData, publishSettings);
} catch (RemoteException e) {
- Log.w(TAG, "createSession/publish RemoteException: " + e);
- return null;
+ throw e.rethrowFromSystemServer();
}
return new WifiNanPublishSession(this, sessionId);
@@ -200,7 +199,7 @@
try {
mService.publish(sessionId, publishData, publishSettings);
} catch (RemoteException e) {
- Log.w(TAG, "publish RemoteException: " + e);
+ throw e.rethrowFromSystemServer();
}
}
/**
@@ -256,8 +255,7 @@
if (DBG) Log.d(TAG, "subscribe: session created - sessionId=" + sessionId);
mService.subscribe(sessionId, subscribeData, subscribeSettings);
} catch (RemoteException e) {
- Log.w(TAG, "createSession/subscribe RemoteException: " + e);
- return null;
+ throw e.rethrowFromSystemServer();
}
return new WifiNanSubscribeSession(this, sessionId);
@@ -286,7 +284,7 @@
try {
mService.subscribe(sessionId, subscribeData, subscribeSettings);
} catch (RemoteException e) {
- Log.w(TAG, "subscribe RemoteException: " + e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -299,7 +297,7 @@
try {
mService.stopSession(sessionId);
} catch (RemoteException e) {
- Log.w(TAG, "stopSession RemoteException (FYI - ignoring): " + e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -312,7 +310,7 @@
try {
mService.destroySession(sessionId);
} catch (RemoteException e) {
- Log.w(TAG, "destroySession RemoteException (FYI - ignoring): " + e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -328,7 +326,7 @@
}
mService.sendMessage(sessionId, peerId, message, messageLength, messageId);
} catch (RemoteException e) {
- Log.w(TAG, "subscribe RemoteException (FYI - ignoring): " + e);
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 6409450..8d5cf63 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1362,8 +1362,8 @@
public void setMiracastMode(int mode) {
try {
mService.setMiracastMode(mode);
- } catch(RemoteException e) {
- // ignore
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1378,7 +1378,7 @@
try {
return mService.getMessenger();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1393,7 +1393,7 @@
try {
return mService.getP2pStateMachineMessenger();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}