diff options
Diffstat (limited to 'core/java/com')
25 files changed, 747 insertions, 178 deletions
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index ea18c12..c1ec6e6 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -659,11 +659,16 @@ public class ChooserActivity extends ResolverActivity { return super.getCount() + mServiceTargets.size() + mCallerTargets.size(); } - public int getCallerTargetsCount() { + @Override + public int getUnfilteredCount() { + return super.getUnfilteredCount() + mServiceTargets.size() + mCallerTargets.size(); + } + + public int getCallerTargetCount() { return mCallerTargets.size(); } - public int getServiceTargetsCount() { + public int getServiceTargetCount() { return mServiceTargets.size(); } @@ -696,6 +701,11 @@ public class ChooserActivity extends ResolverActivity { @Override public TargetInfo getItem(int position) { + return targetInfoForPosition(position, true); + } + + @Override + public TargetInfo targetInfoForPosition(int position, boolean filtered) { int offset = 0; final int callerTargetCount = mCallerTargets.size(); @@ -710,7 +720,8 @@ public class ChooserActivity extends ResolverActivity { } offset += serviceTargetCount; - return super.getItem(position - offset); + return filtered ? super.getItem(position - offset) + : getDisplayInfoAt(position - offset); } public void addServiceResults(DisplayResolveInfo origTarget, List<ChooserTarget> targets) { @@ -764,8 +775,8 @@ public class ChooserActivity extends ResolverActivity { @Override public int getCount() { return (int) ( - Math.ceil((float) mChooserListAdapter.getCallerTargetsCount() / mColumnCount) - + Math.ceil((float) mChooserListAdapter.getServiceTargetsCount() / mColumnCount) + Math.ceil((float) mChooserListAdapter.getCallerTargetCount() / mColumnCount) + + Math.ceil((float) mChooserListAdapter.getServiceTargetCount() / mColumnCount) + Math.ceil((float) mChooserListAdapter.getStandardTargetCount() / mColumnCount) ); } @@ -845,14 +856,14 @@ public class ChooserActivity extends ResolverActivity { } int getFirstRowPosition(int row) { - final int callerCount = mChooserListAdapter.getCallerTargetsCount(); + final int callerCount = mChooserListAdapter.getCallerTargetCount(); final int callerRows = (int) Math.ceil((float) callerCount / mColumnCount); if (row < callerRows) { return row * mColumnCount; } - final int serviceCount = mChooserListAdapter.getServiceTargetsCount(); + final int serviceCount = mChooserListAdapter.getServiceTargetCount(); final int serviceRows = (int) Math.ceil((float) serviceCount / mColumnCount); if (row < callerRows + serviceRows) { diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index 7c5c565..929cacd 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -34,6 +34,12 @@ interface IBatteryStats { void noteStopAudio(int uid); void noteResetVideo(); void noteResetAudio(); + void noteFlashlightOn(int uid); + void noteFlashlightOff(int uid); + void noteStartCamera(int uid); + void noteStopCamera(int uid); + void noteResetCamera(); + void noteResetFlashlight(); // Remaining methods are only used in Java. byte[] getStatistics(); @@ -72,8 +78,6 @@ interface IBatteryStats { void noteVibratorOn(int uid, long durationMillis); void noteVibratorOff(int uid); - void noteFlashlightOn(); - void noteFlashlightOff(); void noteStartGps(int uid); void noteStopGps(int uid); void noteScreenState(int state); diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index 644adb6..a2bd700 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -97,6 +97,11 @@ interface IVoiceInteractionManagerService { void showSessionForActiveService(IVoiceInteractionSessionShowCallback showCallback); /** + * Hides the session from the active service, if it is showing. + */ + void hideCurrentSession(); + + /** * Notifies the active service that a launch was requested from the Keyguard. This will only * be called if {@link #activeServiceSupportsLaunchFromKeyguard()} returns true. */ diff --git a/core/java/com/android/internal/app/IVoiceInteractor.aidl b/core/java/com/android/internal/app/IVoiceInteractor.aidl index 84e9cf0..44feafb 100644 --- a/core/java/com/android/internal/app/IVoiceInteractor.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractor.aidl @@ -27,14 +27,14 @@ import com.android.internal.app.IVoiceInteractorRequest; */ interface IVoiceInteractor { IVoiceInteractorRequest startConfirmation(String callingPackage, - IVoiceInteractorCallback callback, CharSequence prompt, in Bundle extras); + IVoiceInteractorCallback callback, in VoiceInteractor.Prompt prompt, in Bundle extras); IVoiceInteractorRequest startPickOption(String callingPackage, - IVoiceInteractorCallback callback, CharSequence prompt, + IVoiceInteractorCallback callback, in VoiceInteractor.Prompt prompt, in VoiceInteractor.PickOptionRequest.Option[] options, in Bundle extras); IVoiceInteractorRequest startCompleteVoice(String callingPackage, - IVoiceInteractorCallback callback, CharSequence message, in Bundle extras); + IVoiceInteractorCallback callback, in VoiceInteractor.Prompt prompt, in Bundle extras); IVoiceInteractorRequest startAbortVoice(String callingPackage, - IVoiceInteractorCallback callback, CharSequence message, in Bundle extras); + IVoiceInteractorCallback callback, in VoiceInteractor.Prompt prompt, in Bundle extras); IVoiceInteractorRequest startCommand(String callingPackage, IVoiceInteractorCallback callback, String command, in Bundle extras); boolean[] supportsCommands(String callingPackage, in String[] commands); diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 4696757..ba4af89 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -785,7 +785,7 @@ public class ResolverActivity extends Activity { } mAlwaysUseOption = alwaysUseOption; - int count = mAdapter.mDisplayList.size(); + int count = mAdapter.getUnfilteredCount(); if (count > 1 || (count == 1 && mAdapter.getOtherProfile() != null)) { setContentView(layoutId); mAdapterView = (AbsListView) findViewById(R.id.resolver_list); @@ -1392,6 +1392,18 @@ public class ResolverActivity extends Activity { return result; } + public int getUnfilteredCount() { + return mDisplayList.size(); + } + + public int getDisplayInfoCount() { + return mDisplayList.size(); + } + + public DisplayResolveInfo getDisplayInfoAt(int index) { + return mDisplayList.get(index); + } + public TargetInfo getItem(int position) { if (mFilterLastUsed && mLastChosenPosition >= 0 && position >= mLastChosenPosition) { position++; diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java index ce94727..e607a3f 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java +++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.text.TextUtils; import android.util.Log; +import android.util.Printer; import android.util.Slog; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; @@ -314,6 +315,15 @@ public class InputMethodSubtypeSwitchingController { } return null; } + + protected void dump(final Printer pw, final String prefix) { + final int N = mImeSubtypeList.size(); + for (int i = 0; i < N; ++i) { + final int rank = i; + final ImeSubtypeListItem item = mImeSubtypeList.get(i); + pw.println(prefix + "rank=" + rank + " item=" + item); + } + } } private static class DynamicRotationList { @@ -388,6 +398,14 @@ public class InputMethodSubtypeSwitchingController { } return null; } + + protected void dump(final Printer pw, final String prefix) { + for (int i = 0; i < mUsageHistoryOfSubtypeListItemIndex.length; ++i) { + final int rank = mUsageHistoryOfSubtypeListItemIndex[i]; + final ImeSubtypeListItem item = mImeSubtypeList.get(i); + pw.println(prefix + "rank=" + rank + " item=" + item); + } + } } @VisibleForTesting @@ -478,6 +496,13 @@ public class InputMethodSubtypeSwitchingController { } return result; } + + protected void dump(final Printer pw) { + pw.println(" mSwitchingAwareRotationList:"); + mSwitchingAwareRotationList.dump(pw, " "); + pw.println(" mSwitchingUnawareRotationList:"); + mSwitchingUnawareRotationList.dump(pw, " "); + } } private final InputMethodSettings mSettings; @@ -526,4 +551,12 @@ public class InputMethodSubtypeSwitchingController { return mSubtypeList.getSortedInputMethodAndSubtypeList( showSubtypes, includingAuxiliarySubtypes, isScreenLocked); } + + public void dump(final Printer pw) { + if (mController != null) { + mController.dump(pw); + } else { + pw.println(" mController=null"); + } + } } diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java index 06bdb24..042db71 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java +++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java @@ -379,6 +379,14 @@ public class InputMethodUtils { // The length of localeStr is guaranteed to always return a 1 <= value <= 3 // because localeStr is not empty. if (localeParams.length == 1) { + if (localeParams.length >= 1 && "tl".equals(localeParams[0])) { + // Convert a locale whose language is "tl" to one whose language is "fil". + // For example, "tl_PH" will get converted to "fil_PH". + // Versions of Android earlier than Lollipop did not support three letter language + // codes, and used "tl" (Tagalog) as the language string for "fil" (Filipino). + // On Lollipop and above, the current three letter version must be used. + localeParams[0] = "fil"; + } return new Locale(localeParams[0]); } else if (localeParams.length == 2) { return new Locale(localeParams[0], localeParams[1]); @@ -397,7 +405,7 @@ public class InputMethodUtils { for (int i = 0; i < N; ++i) { final InputMethodSubtype subtype = imi.getSubtypeAt(i); if (checkCountry) { - final Locale subtypeLocale = constructLocaleFromString(subtype.getLocale()); + final Locale subtypeLocale = subtype.getLocaleObject(); if (subtypeLocale == null || !TextUtils.equals(subtypeLocale.getLanguage(), locale.getLanguage()) || !TextUtils.equals(subtypeLocale.getCountry(), locale.getCountry())) { diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index 230d96d..2f21efd 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -27,6 +27,7 @@ import android.view.View; */ public class MetricsLogger implements MetricsConstants { // Temporary constants go here, to await migration to MetricsConstants. + public static final int ACTION_EMERGENCY_CALL = 200; public static void visible(Context context, int category) throws IllegalArgumentException { if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) { diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java index 056b0aa..049d3eb 100644 --- a/core/java/com/android/internal/os/BatterySipper.java +++ b/core/java/com/android/internal/os/BatterySipper.java @@ -42,6 +42,8 @@ public class BatterySipper implements Comparable<BatterySipper> { public long wifiRunningTimeMs; public long cpuFgTimeMs; public long wakeLockTimeMs; + public long cameraTimeMs; + public long flashlightTimeMs; public long mobileRxPackets; public long mobileTxPackets; @@ -67,6 +69,8 @@ public class BatterySipper implements Comparable<BatterySipper> { public double mobileRadioPowerMah; public double gpsPowerMah; public double sensorPowerMah; + public double cameraPowerMah; + public double flashlightPowerMah; public enum DrainType { IDLE, @@ -79,7 +83,8 @@ public class BatterySipper implements Comparable<BatterySipper> { APP, USER, UNACCOUNTED, - OVERCOUNTED + OVERCOUNTED, + CAMERA } public BatterySipper(DrainType drainType, Uid uid, double value) { @@ -135,6 +140,8 @@ public class BatterySipper implements Comparable<BatterySipper> { wifiRunningTimeMs += other.wifiRunningTimeMs; cpuFgTimeMs += other.cpuFgTimeMs; wakeLockTimeMs += other.wakeLockTimeMs; + cameraTimeMs += other.cameraTimeMs; + flashlightTimeMs += other.flashlightTimeMs; mobileRxPackets += other.mobileRxPackets; mobileTxPackets += other.mobileTxPackets; mobileActive += other.mobileActive; @@ -151,6 +158,8 @@ public class BatterySipper implements Comparable<BatterySipper> { sensorPowerMah += other.sensorPowerMah; mobileRadioPowerMah += other.mobileRadioPowerMah; wakeLockPowerMah += other.wakeLockPowerMah; + cameraPowerMah += other.cameraPowerMah; + flashlightPowerMah += other.flashlightPowerMah; } /** @@ -158,7 +167,8 @@ public class BatterySipper implements Comparable<BatterySipper> { * @return the sum of all the power in this BatterySipper. */ public double sumPower() { - return totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah + sensorPowerMah - + mobileRadioPowerMah + wakeLockPowerMah; + return totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah + + sensorPowerMah + mobileRadioPowerMah + wakeLockPowerMah + cameraPowerMah + + flashlightPowerMah; } } diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java index fbe87c5..e6165a1 100644 --- a/core/java/com/android/internal/os/BatteryStatsHelper.java +++ b/core/java/com/android/internal/os/BatteryStatsHelper.java @@ -122,6 +122,8 @@ public final class BatteryStatsHelper { PowerCalculator mWifiPowerCalculator; PowerCalculator mBluetoothPowerCalculator; PowerCalculator mSensorPowerCalculator; + PowerCalculator mCameraPowerCalculator; + PowerCalculator mFlashlightPowerCalculator; public static boolean checkWifiOnly(Context context) { ConnectivityManager cm = (ConnectivityManager)context.getSystemService( @@ -365,6 +367,16 @@ public final class BatteryStatsHelper { } mSensorPowerCalculator.reset(); + if (mCameraPowerCalculator == null) { + mCameraPowerCalculator = new CameraPowerCalculator(mPowerProfile); + } + mCameraPowerCalculator.reset(); + + if (mFlashlightPowerCalculator == null) { + mFlashlightPowerCalculator = new FlashlightPowerCalculator(mPowerProfile); + } + mFlashlightPowerCalculator.reset(); + mStatsType = statsType; mRawUptime = rawUptimeUs; mRawRealtime = rawRealtimeUs; @@ -480,6 +492,8 @@ public final class BatteryStatsHelper { mWifiPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); mSensorPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); + mCameraPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); + mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); final double totalPower = app.sumPower(); if (DEBUG && totalPower != 0) { @@ -619,15 +633,6 @@ public final class BatteryStatsHelper { } } - private void addFlashlightUsage() { - long flashlightOnTimeMs = mStats.getFlashlightOnTime(mRawRealtime, mStatsType) / 1000; - double flashlightPower = flashlightOnTimeMs - * mPowerProfile.getAveragePower(PowerProfile.POWER_FLASHLIGHT) / (60*60*1000); - if (flashlightPower != 0) { - addEntry(BatterySipper.DrainType.FLASHLIGHT, flashlightOnTimeMs, flashlightPower); - } - } - private void addUserUsage() { for (int i = 0; i < mUserSippers.size(); i++) { final int userId = mUserSippers.keyAt(i); @@ -643,7 +648,6 @@ public final class BatteryStatsHelper { addUserUsage(); addPhoneUsage(); addScreenUsage(); - addFlashlightUsage(); addWiFiUsage(); addBluetoothUsage(); addIdleUsage(); // Not including cellular idle power diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index eaca43b..ee7ed0b 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -105,7 +105,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 126 + (USE_OLD_HISTORY ? 1000 : 0); + private static final int VERSION = 127 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -211,6 +211,8 @@ public final class BatteryStatsImpl extends BatteryStats { final SparseArray<ArrayList<StopwatchTimer>> mWifiBatchedScanTimers = new SparseArray<>(); final ArrayList<StopwatchTimer> mAudioTurnedOnTimers = new ArrayList<>(); final ArrayList<StopwatchTimer> mVideoTurnedOnTimers = new ArrayList<>(); + final ArrayList<StopwatchTimer> mFlashlightTurnedOnTimers = new ArrayList<>(); + final ArrayList<StopwatchTimer> mCameraTurnedOnTimers = new ArrayList<>(); // Last partial timers we use for distributing CPU usage. final ArrayList<StopwatchTimer> mLastPartialTimers = new ArrayList<>(); @@ -270,18 +272,19 @@ public final class BatteryStatsImpl extends BatteryStats { final HistoryStepDetails mCurHistoryStepDetails = new HistoryStepDetails(); final HistoryStepDetails mReadHistoryStepDetails = new HistoryStepDetails(); final HistoryStepDetails mTmpHistoryStepDetails = new HistoryStepDetails(); + /** - * Total time (in 1/100 sec) spent executing in user code. + * Total time (in milliseconds) spent executing in user code. */ long mLastStepCpuUserTime; long mCurStepCpuUserTime; /** - * Total time (in 1/100 sec) spent executing in kernel code. + * Total time (in milliseconds) spent executing in kernel code. */ long mLastStepCpuSystemTime; long mCurStepCpuSystemTime; /** - * Times from /proc/stat + * Times from /proc/stat (but measured in milliseconds). */ long mLastStepStatUserTime; long mLastStepStatSystemTime; @@ -343,9 +346,12 @@ public final class BatteryStatsImpl extends BatteryStats { int mVideoOnNesting; StopwatchTimer mVideoOnTimer; - boolean mFlashlightOn; + int mFlashlightOnNesting; StopwatchTimer mFlashlightOnTimer; + int mCameraOnNesting; + StopwatchTimer mCameraOnTimer; + int mPhoneSignalStrengthBin = -1; int mPhoneSignalStrengthBinRaw = -1; final StopwatchTimer[] mPhoneSignalStrengthsTimer = @@ -3710,30 +3716,100 @@ public final class BatteryStatsImpl extends BatteryStats { getUidStatsLocked(uid).noteVibratorOffLocked(); } - public void noteFlashlightOnLocked() { - if (!mFlashlightOn) { - final long elapsedRealtime = SystemClock.elapsedRealtime(); - final long uptime = SystemClock.uptimeMillis(); + public void noteFlashlightOnLocked(int uid) { + uid = mapUid(uid); + final long elapsedRealtime = SystemClock.elapsedRealtime(); + final long uptime = SystemClock.uptimeMillis(); + if (mFlashlightOnNesting++ == 0) { mHistoryCur.states2 |= HistoryItem.STATE2_FLASHLIGHT_FLAG; if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight on to: " - + Integer.toHexString(mHistoryCur.states)); + + Integer.toHexString(mHistoryCur.states2)); addHistoryRecordLocked(elapsedRealtime, uptime); - mFlashlightOn = true; mFlashlightOnTimer.startRunningLocked(elapsedRealtime); } + getUidStatsLocked(uid).noteFlashlightTurnedOnLocked(elapsedRealtime); } - public void noteFlashlightOffLocked() { + public void noteFlashlightOffLocked(int uid) { + if (mFlashlightOnNesting == 0) { + return; + } + uid = mapUid(uid); final long elapsedRealtime = SystemClock.elapsedRealtime(); final long uptime = SystemClock.uptimeMillis(); - if (mFlashlightOn) { + if (--mFlashlightOnNesting == 0) { mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG; if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: " - + Integer.toHexString(mHistoryCur.states)); + + Integer.toHexString(mHistoryCur.states2)); addHistoryRecordLocked(elapsedRealtime, uptime); - mFlashlightOn = false; mFlashlightOnTimer.stopRunningLocked(elapsedRealtime); } + getUidStatsLocked(uid).noteFlashlightTurnedOffLocked(elapsedRealtime); + } + + public void noteCameraOnLocked(int uid) { + uid = mapUid(uid); + final long elapsedRealtime = SystemClock.elapsedRealtime(); + final long uptime = SystemClock.uptimeMillis(); + if (mCameraOnNesting++ == 0) { + mHistoryCur.states2 |= HistoryItem.STATE2_CAMERA_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Camera on to: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtime, uptime); + mCameraOnTimer.startRunningLocked(elapsedRealtime); + } + getUidStatsLocked(uid).noteCameraTurnedOnLocked(elapsedRealtime); + } + + public void noteCameraOffLocked(int uid) { + if (mCameraOnNesting == 0) { + return; + } + uid = mapUid(uid); + final long elapsedRealtime = SystemClock.elapsedRealtime(); + final long uptime = SystemClock.uptimeMillis(); + if (--mCameraOnNesting == 0) { + mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtime, uptime); + mCameraOnTimer.stopRunningLocked(elapsedRealtime); + } + getUidStatsLocked(uid).noteCameraTurnedOffLocked(elapsedRealtime); + } + + public void noteResetCameraLocked() { + if (mCameraOnNesting > 0) { + final long elapsedRealtime = SystemClock.elapsedRealtime(); + final long uptime = SystemClock.uptimeMillis(); + mCameraOnNesting = 0; + mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtime, uptime); + mCameraOnTimer.stopAllRunningLocked(elapsedRealtime); + for (int i=0; i<mUidStats.size(); i++) { + BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); + uid.noteResetCameraLocked(elapsedRealtime); + } + } + } + + public void noteResetFlashlightLocked() { + if (mFlashlightOnNesting > 0) { + final long elapsedRealtime = SystemClock.elapsedRealtime(); + final long uptime = SystemClock.uptimeMillis(); + mFlashlightOnNesting = 0; + mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtime, uptime); + mFlashlightOnTimer.stopAllRunningLocked(elapsedRealtime); + for (int i=0; i<mUidStats.size(); i++) { + BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); + uid.noteResetFlashlightLocked(elapsedRealtime); + } + } } public void noteWifiRadioPowerState(int powerState, long timestampNs) { @@ -4262,15 +4338,22 @@ public final class BatteryStatsImpl extends BatteryStats { return 0; } - @Override public long getFlashlightOnTime(long elapsedRealtimeUs, int which) { + @Override + public long getFlashlightOnTime(long elapsedRealtimeUs, int which) { return mFlashlightOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which); } - @Override public long getFlashlightOnCount(int which) { + @Override + public long getFlashlightOnCount(int which) { return mFlashlightOnTimer.getCountLocked(which); } @Override + public long getCameraOnTime(long elapsedRealtimeUs, int which) { + return mCameraOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which); + } + + @Override public long getNetworkActivityBytes(int type, int which) { if (type >= 0 && type < mNetworkByteActivityCounters.length) { return mNetworkByteActivityCounters[type].getCountLocked(which); @@ -4350,6 +4433,9 @@ public final class BatteryStatsImpl extends BatteryStats { StopwatchTimer mAudioTurnedOnTimer; StopwatchTimer mVideoTurnedOnTimer; + StopwatchTimer mFlashlightTurnedOnTimer; + StopwatchTimer mCameraTurnedOnTimer; + StopwatchTimer mForegroundActivityTimer; @@ -4650,6 +4736,54 @@ public final class BatteryStatsImpl extends BatteryStats { } } + public StopwatchTimer createFlashlightTurnedOnTimerLocked() { + if (mFlashlightTurnedOnTimer == null) { + mFlashlightTurnedOnTimer = new StopwatchTimer(Uid.this, FLASHLIGHT_TURNED_ON, + mFlashlightTurnedOnTimers, mOnBatteryTimeBase); + } + return mFlashlightTurnedOnTimer; + } + + public void noteFlashlightTurnedOnLocked(long elapsedRealtimeMs) { + createFlashlightTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs); + } + + public void noteFlashlightTurnedOffLocked(long elapsedRealtimeMs) { + if (mFlashlightTurnedOnTimer != null) { + mFlashlightTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs); + } + } + + public void noteResetFlashlightLocked(long elapsedRealtimeMs) { + if (mFlashlightTurnedOnTimer != null) { + mFlashlightTurnedOnTimer.stopAllRunningLocked(elapsedRealtimeMs); + } + } + + public StopwatchTimer createCameraTurnedOnTimerLocked() { + if (mCameraTurnedOnTimer == null) { + mCameraTurnedOnTimer = new StopwatchTimer(Uid.this, CAMERA_TURNED_ON, + mCameraTurnedOnTimers, mOnBatteryTimeBase); + } + return mCameraTurnedOnTimer; + } + + public void noteCameraTurnedOnLocked(long elapsedRealtimeMs) { + createCameraTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs); + } + + public void noteCameraTurnedOffLocked(long elapsedRealtimeMs) { + if (mCameraTurnedOnTimer != null) { + mCameraTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs); + } + } + + public void noteResetCameraLocked(long elapsedRealtimeMs) { + if (mCameraTurnedOnTimer != null) { + mCameraTurnedOnTimer.stopAllRunningLocked(elapsedRealtimeMs); + } + } + public StopwatchTimer createForegroundActivityTimerLocked() { if (mForegroundActivityTimer == null) { mForegroundActivityTimer = new StopwatchTimer( @@ -4762,19 +4896,23 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override - public long getAudioTurnedOnTime(long elapsedRealtimeUs, int which) { - if (mAudioTurnedOnTimer == null) { - return 0; - } - return mAudioTurnedOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which); + public Timer getAudioTurnedOnTimer() { + return mAudioTurnedOnTimer; } @Override - public long getVideoTurnedOnTime(long elapsedRealtimeUs, int which) { - if (mVideoTurnedOnTimer == null) { - return 0; - } - return mVideoTurnedOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which); + public Timer getVideoTurnedOnTimer() { + return mVideoTurnedOnTimer; + } + + @Override + public Timer getFlashlightTurnedOnTimer() { + return mFlashlightTurnedOnTimer; + } + + @Override + public Timer getCameraTurnedOnTimer() { + return mCameraTurnedOnTimer; } @Override @@ -4994,6 +5132,12 @@ public final class BatteryStatsImpl extends BatteryStats { if (mVideoTurnedOnTimer != null) { active |= !mVideoTurnedOnTimer.reset(false); } + if (mFlashlightTurnedOnTimer != null) { + active |= !mFlashlightTurnedOnTimer.reset(false); + } + if (mCameraTurnedOnTimer != null) { + active |= !mCameraTurnedOnTimer.reset(false); + } if (mForegroundActivityTimer != null) { active |= !mForegroundActivityTimer.reset(false); } @@ -5155,6 +5299,14 @@ public final class BatteryStatsImpl extends BatteryStats { mVideoTurnedOnTimer.detach(); mVideoTurnedOnTimer = null; } + if (mFlashlightTurnedOnTimer != null) { + mFlashlightTurnedOnTimer.detach(); + mFlashlightTurnedOnTimer = null; + } + if (mCameraTurnedOnTimer != null) { + mCameraTurnedOnTimer.detach(); + mCameraTurnedOnTimer = null; + } if (mForegroundActivityTimer != null) { mForegroundActivityTimer.detach(); mForegroundActivityTimer = null; @@ -5291,6 +5443,18 @@ public final class BatteryStatsImpl extends BatteryStats { } else { out.writeInt(0); } + if (mFlashlightTurnedOnTimer != null) { + out.writeInt(1); + mFlashlightTurnedOnTimer.writeToParcel(out, elapsedRealtimeUs); + } else { + out.writeInt(0); + } + if (mCameraTurnedOnTimer != null) { + out.writeInt(1); + mCameraTurnedOnTimer.writeToParcel(out, elapsedRealtimeUs); + } else { + out.writeInt(0); + } if (mForegroundActivityTimer != null) { out.writeInt(1); mForegroundActivityTimer.writeToParcel(out, elapsedRealtimeUs); @@ -5469,6 +5633,18 @@ public final class BatteryStatsImpl extends BatteryStats { mVideoTurnedOnTimer = null; } if (in.readInt() != 0) { + mFlashlightTurnedOnTimer = new StopwatchTimer(Uid.this, FLASHLIGHT_TURNED_ON, + mFlashlightTurnedOnTimers, mOnBatteryTimeBase, in); + } else { + mFlashlightTurnedOnTimer = null; + } + if (in.readInt() != 0) { + mCameraTurnedOnTimer = new StopwatchTimer(Uid.this, CAMERA_TURNED_ON, + mCameraTurnedOnTimers, mOnBatteryTimeBase, in); + } else { + mCameraTurnedOnTimer = null; + } + if (in.readInt() != 0) { mForegroundActivityTimer = new StopwatchTimer( Uid.this, FOREGROUND_ACTIVITY, null, mOnBatteryTimeBase, in); } else { @@ -6700,6 +6876,7 @@ public final class BatteryStatsImpl extends BatteryStats { mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase); mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase); mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase); + mCameraOnTimer = new StopwatchTimer(null, -13, null, mOnBatteryTimeBase); mOnBattery = mOnBatteryInternal = false; long uptime = SystemClock.uptimeMillis() * 1000; long realtime = SystemClock.elapsedRealtime() * 1000; @@ -7285,6 +7462,7 @@ public final class BatteryStatsImpl extends BatteryStats { mAudioOnTimer.reset(false); mVideoOnTimer.reset(false); mFlashlightOnTimer.reset(false); + mCameraOnTimer.reset(false); for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) { mPhoneSignalStrengthsTimer[i].reset(false); } @@ -8811,8 +8989,10 @@ public final class BatteryStatsImpl extends BatteryStats { } mNumConnectivityChange = mLoadedNumConnectivityChange = in.readInt(); - mFlashlightOn = false; + mFlashlightOnNesting = 0; mFlashlightOnTimer.readSummaryFromParcelLocked(in); + mCameraOnNesting = 0; + mCameraOnTimer.readSummaryFromParcelLocked(in); int NKW = in.readInt(); if (NKW > 10000) { @@ -8883,6 +9063,12 @@ public final class BatteryStatsImpl extends BatteryStats { u.createVideoTurnedOnTimerLocked().readSummaryFromParcelLocked(in); } if (in.readInt() != 0) { + u.createFlashlightTurnedOnTimerLocked().readSummaryFromParcelLocked(in); + } + if (in.readInt() != 0) { + u.createCameraTurnedOnTimerLocked().readSummaryFromParcelLocked(in); + } + if (in.readInt() != 0) { u.createForegroundActivityTimerLocked().readSummaryFromParcelLocked(in); } u.mProcessState = Uid.PROCESS_STATE_NONE; @@ -9132,6 +9318,7 @@ public final class BatteryStatsImpl extends BatteryStats { } out.writeInt(mNumConnectivityChange); mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); + mCameraOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); out.writeInt(mKernelWakelockStats.size()); for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) { @@ -9208,6 +9395,18 @@ public final class BatteryStatsImpl extends BatteryStats { } else { out.writeInt(0); } + if (u.mFlashlightTurnedOnTimer != null) { + out.writeInt(1); + u.mFlashlightTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); + } else { + out.writeInt(0); + } + if (u.mCameraTurnedOnTimer != null) { + out.writeInt(1); + u.mCameraTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); + } else { + out.writeInt(0); + } if (u.mForegroundActivityTimer != null) { out.writeInt(1); u.mForegroundActivityTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); @@ -9453,8 +9652,10 @@ public final class BatteryStatsImpl extends BatteryStats { mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase); mVideoOnNesting = 0; mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase); - mFlashlightOn = false; + mFlashlightOnNesting = 0; mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase, in); + mCameraOnNesting = 0; + mCameraOnTimer = new StopwatchTimer(null, -13, null, mOnBatteryTimeBase, in); mDischargeUnplugLevel = in.readInt(); mDischargePlugLevel = in.readInt(); mDischargeCurrentLevel = in.readInt(); @@ -9499,6 +9700,8 @@ public final class BatteryStatsImpl extends BatteryStats { mWifiMulticastTimers.clear(); mAudioTurnedOnTimers.clear(); mVideoTurnedOnTimers.clear(); + mFlashlightTurnedOnTimers.clear(); + mCameraTurnedOnTimers.clear(); sNumSpeedSteps = in.readInt(); @@ -9598,6 +9801,7 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(mLoadedNumConnectivityChange); out.writeInt(mUnpluggedNumConnectivityChange); mFlashlightOnTimer.writeToParcel(out, uSecRealtime); + mCameraOnTimer.writeToParcel(out, uSecRealtime); out.writeInt(mDischargeUnplugLevel); out.writeInt(mDischargePlugLevel); out.writeInt(mDischargeCurrentLevel); @@ -9732,6 +9936,8 @@ public final class BatteryStatsImpl extends BatteryStats { } pr.println("*** Flashlight timer:"); mFlashlightOnTimer.logState(pr, " "); + pr.println("*** Camera timer:"); + mCameraOnTimer.logState(pr, " "); } super.dumpLocked(context, pw, flags, reqUid, histStart); } diff --git a/core/java/com/android/internal/os/CameraPowerCalculator.java b/core/java/com/android/internal/os/CameraPowerCalculator.java new file mode 100644 index 0000000..3273080 --- /dev/null +++ b/core/java/com/android/internal/os/CameraPowerCalculator.java @@ -0,0 +1,48 @@ +/* + * 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.internal.os; + +import android.os.BatteryStats; + +/** + * Power calculator for the camera subsystem, excluding the flashlight. + * + * Note: Power draw for the flash unit should be included in the FlashlightPowerCalculator. + */ +public class CameraPowerCalculator extends PowerCalculator { + private final double mCameraPowerOnAvg; + + public CameraPowerCalculator(PowerProfile profile) { + mCameraPowerOnAvg = profile.getAveragePower(PowerProfile.POWER_CAMERA); + } + + @Override + public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, + long rawUptimeUs, int statsType) { + + // Calculate camera power usage. Right now, this is a (very) rough estimate based on the + // average power usage for a typical camera application. + final BatteryStats.Timer timer = u.getCameraTurnedOnTimer(); + if (timer != null) { + final long totalTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000; + app.cameraTimeMs = totalTime; + app.cameraPowerMah = (totalTime * mCameraPowerOnAvg) / (1000*60*60); + } else { + app.cameraTimeMs = 0; + app.cameraPowerMah = 0; + } + } +} diff --git a/core/java/com/android/internal/os/FlashlightPowerCalculator.java b/core/java/com/android/internal/os/FlashlightPowerCalculator.java new file mode 100644 index 0000000..fef66ff --- /dev/null +++ b/core/java/com/android/internal/os/FlashlightPowerCalculator.java @@ -0,0 +1,46 @@ +/* + * 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.internal.os; + +import android.os.BatteryStats; + +/** + * Power calculator for the flashlight. + */ +public class FlashlightPowerCalculator extends PowerCalculator { + private final double mFlashlightPowerOnAvg; + + public FlashlightPowerCalculator(PowerProfile profile) { + mFlashlightPowerOnAvg = profile.getAveragePower(PowerProfile.POWER_FLASHLIGHT); + } + + @Override + public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, + long rawUptimeUs, int statsType) { + + // Calculate flashlight power usage. Right now, this is based on the average power draw + // of the flash unit when kept on over a short period of time. + final BatteryStats.Timer timer = u.getFlashlightTurnedOnTimer(); + if (timer != null) { + final long totalTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000; + app.flashlightTimeMs = totalTime; + app.flashlightPowerMah = (totalTime * mFlashlightPowerOnAvg) / (1000*60*60); + } else { + app.flashlightTimeMs = 0; + app.flashlightPowerMah = 0; + } + } +} diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java index 1efa565..4ede8dd 100644 --- a/core/java/com/android/internal/os/PowerProfile.java +++ b/core/java/com/android/internal/os/PowerProfile.java @@ -152,10 +152,17 @@ public class PowerProfile { public static final String POWER_VIDEO = "dsp.video"; /** - * Power consumption when camera flashlight is on. + * Average power consumption when camera flashlight is on. */ public static final String POWER_FLASHLIGHT = "camera.flashlight"; + /** + * Average power consumption when the camera is on over all standard use cases. + * + * TODO: Add more fine-grained camera power metrics. + */ + public static final String POWER_CAMERA = "camera.avg"; + public static final String POWER_CPU_SPEEDS = "cpu.speeds"; /** diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java index 8393e2a..bf97f1f 100644 --- a/core/java/com/android/internal/os/ProcessCpuTracker.java +++ b/core/java/com/android/internal/os/ProcessCpuTracker.java @@ -139,6 +139,8 @@ public class ProcessCpuTracker { private float mLoad5 = 0; private float mLoad15 = 0; + // All times are in milliseconds. They are converted from jiffies to milliseconds + // when extracted from the kernel. private long mCurrentSampleTime; private long mLastSampleTime; @@ -191,12 +193,34 @@ public class ProcessCpuTracker { // filter out kernel processes. public long vsize; + /** + * Time in milliseconds. + */ public long base_uptime; + + /** + * Time in milliseconds. + */ public long rel_uptime; + /** + * Time in milliseconds. + */ public long base_utime; + + /** + * Time in milliseconds. + */ public long base_stime; + + /** + * Time in milliseconds. + */ public int rel_utime; + + /** + * Time in milliseconds. + */ public int rel_stime; public long base_minfaults; @@ -558,7 +582,7 @@ public class ProcessCpuTracker { } /** - * Returns the total time (in clock ticks, or 1/100 sec) spent executing in + * Returns the total time (in milliseconds) spent executing in * both user and system code. Safe to call without lock held. */ public long getCpuTimeForPid(int pid) { @@ -575,26 +599,44 @@ public class ProcessCpuTracker { } } + /** + * @return time in milliseconds. + */ final public int getLastUserTime() { return mRelUserTime; } + /** + * @return time in milliseconds. + */ final public int getLastSystemTime() { return mRelSystemTime; } + /** + * @return time in milliseconds. + */ final public int getLastIoWaitTime() { return mRelIoWaitTime; } + /** + * @return time in milliseconds. + */ final public int getLastIrqTime() { return mRelIrqTime; } + /** + * @return time in milliseconds. + */ final public int getLastSoftIrqTime() { return mRelSoftIrqTime; } + /** + * @return time in milliseconds. + */ final public int getLastIdleTime() { return mRelIdleTime; } diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java index c977997..b0d24fd 100644 --- a/core/java/com/android/internal/os/SomeArgs.java +++ b/core/java/com/android/internal/os/SomeArgs.java @@ -46,6 +46,7 @@ public final class SomeArgs { public Object arg4; public Object arg5; public Object arg6; + public Object arg7; public int argi1; public int argi2; public int argi3; @@ -97,6 +98,7 @@ public final class SomeArgs { arg4 = null; arg5 = null; arg6 = null; + arg7 = null; argi1 = 0; argi2 = 0; argi3 = 0; diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 5ed4f70..971da77 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -508,7 +508,7 @@ public class ZygoteInit { String args[] = { "--setuid=1000", "--setgid=1000", - "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007", + "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007", "--capabilities=" + capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl index f93b1a1..7ab4651 100644 --- a/core/java/com/android/internal/policy/IKeyguardService.aidl +++ b/core/java/com/android/internal/policy/IKeyguardService.aidl @@ -22,6 +22,7 @@ import com.android.internal.policy.IKeyguardExitCallback; import android.os.Bundle; oneway interface IKeyguardService { + /** * Sets the Keyguard as occluded when a window dismisses the Keyguard with flag * FLAG_SHOW_ON_LOCK_SCREEN. @@ -36,8 +37,27 @@ oneway interface IKeyguardService { void dismiss(); void onDreamingStarted(); void onDreamingStopped(); - void onScreenTurnedOff(int reason); - void onScreenTurnedOn(IKeyguardShowCallback callback); + + /** + * Called when the device has started going to sleep. + * + * @param why {@link #OFF_BECAUSE_OF_USER}, {@link #OFF_BECAUSE_OF_ADMIN}, + * or {@link #OFF_BECAUSE_OF_TIMEOUT}. + */ + void onStartedGoingToSleep(int reason); + + /** + * Called when the device has finished going to sleep. + * + * @param why {@link #OFF_BECAUSE_OF_USER}, {@link #OFF_BECAUSE_OF_ADMIN}, + * or {@link #OFF_BECAUSE_OF_TIMEOUT}. + */ + void onFinishedGoingToSleep(int reason); + + /** + * Called when the device has started waking up. + */ + void onStartedWakingUp(IKeyguardShowCallback callback); void setKeyguardEnabled(boolean enabled); void onSystemReady(); void doKeyguardTimeout(in Bundle options); diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index bc64373..c010dfe 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -56,7 +56,6 @@ import android.view.Window; import android.view.WindowInsets; import android.view.WindowManager; import com.android.internal.R; -import com.android.internal.util.ScreenShapeHelper; import com.android.internal.view.FloatingActionMode; import com.android.internal.view.RootViewSurfaceTaker; import com.android.internal.view.StandaloneActionMode; @@ -76,6 +75,7 @@ import com.android.internal.widget.SwipeDismissLayout; import android.app.ActivityManager; import android.app.KeyguardManager; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources.Theme; @@ -156,7 +156,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { TypedValue mFixedWidthMinor; TypedValue mFixedHeightMajor; TypedValue mFixedHeightMinor; - int mOutsetBottomPx; // This is the top-level view of the window, containing the window decor. private DecorView mDecor; @@ -289,6 +288,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private Boolean mSharedElementsUseOverlay; private Rect mTempRect; + private Rect mOutsets = new Rect(); + + private boolean mIsStartingWindow; static class WindowManagerHolder { static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface( @@ -2220,12 +2222,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private final ColorViewState mStatusColorViewState = new ColorViewState( SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS, Gravity.TOP, + Gravity.LEFT, STATUS_BAR_BACKGROUND_TRANSITION_NAME, com.android.internal.R.id.statusBarBackground, FLAG_FULLSCREEN); private final ColorViewState mNavigationColorViewState = new ColorViewState( SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION, Gravity.BOTTOM, + Gravity.RIGHT, NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME, com.android.internal.R.id.navigationBarBackground, 0 /* hideWindowFlag */); @@ -2241,6 +2245,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private int mLastRightInset = 0; private boolean mLastHasTopStableInset = false; private boolean mLastHasBottomStableInset = false; + private boolean mLastHasRightStableInset = false; private int mLastWindowFlags = 0; private int mRootScrollY = 0; @@ -2401,19 +2406,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } @Override - public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { - if (mOutsetBottomPx != 0) { - WindowInsets newInsets = insets.replaceSystemWindowInsets( - insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), - insets.getSystemWindowInsetRight(), mOutsetBottomPx); - return super.dispatchApplyWindowInsets(newInsets); - } else { - return super.dispatchApplyWindowInsets(insets); - } - } - - - @Override public boolean onTouchEvent(MotionEvent event) { return onInterceptTouchEvent(event); } @@ -2624,11 +2616,21 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } - if (mOutsetBottomPx != 0) { + getOutsets(mOutsets); + if (mOutsets.top > 0 || mOutsets.bottom > 0) { int mode = MeasureSpec.getMode(heightMeasureSpec); if (mode != MeasureSpec.UNSPECIFIED) { int height = MeasureSpec.getSize(heightMeasureSpec); - heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + mOutsetBottomPx, mode); + heightMeasureSpec = MeasureSpec.makeMeasureSpec( + height + mOutsets.top + mOutsets.bottom, mode); + } + } + if (mOutsets.left > 0 || mOutsets.right > 0) { + int mode = MeasureSpec.getMode(widthMeasureSpec); + if (mode != MeasureSpec.UNSPECIFIED) { + int width = MeasureSpec.getSize(widthMeasureSpec); + widthMeasureSpec = MeasureSpec.makeMeasureSpec( + width + mOutsets.left + mOutsets.right, mode); } } @@ -2666,6 +2668,18 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + getOutsets(mOutsets); + if (mOutsets.left > 0) { + offsetLeftAndRight(-mOutsets.left); + } + if (mOutsets.top > 0) { + offsetTopAndBottom(-mOutsets.top); + } + } + + @Override public void draw(Canvas canvas) { super.draw(canvas); @@ -2674,7 +2688,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } - @Override public boolean showContextMenuForChild(View originalView) { // Reuse the context menu builder @@ -2875,12 +2888,19 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { boolean hasBottomStableInset = insets.getStableInsetBottom() != 0; disallowAnimate |= (hasBottomStableInset != mLastHasBottomStableInset); mLastHasBottomStableInset = hasBottomStableInset; + + boolean hasRightStableInset = insets.getStableInsetRight() != 0; + disallowAnimate |= (hasRightStableInset != mLastHasRightStableInset); + mLastHasRightStableInset = hasRightStableInset; } updateColorViewInt(mStatusColorViewState, sysUiVisibility, mStatusBarColor, - mLastTopInset, animate && !disallowAnimate); + mLastTopInset, false /* matchVertical */, animate && !disallowAnimate); + + boolean navBarToRightEdge = mLastBottomInset == 0 && mLastRightInset > 0; + int navBarSize = navBarToRightEdge ? mLastRightInset : mLastBottomInset; updateColorViewInt(mNavigationColorViewState, sysUiVisibility, mNavigationBarColor, - mLastBottomInset, animate && !disallowAnimate); + navBarSize, navBarToRightEdge, animate && !disallowAnimate); } // When we expand the window with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, we still need @@ -2924,9 +2944,20 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return insets; } + /** + * Update a color view + * + * @param state the color view to update. + * @param sysUiVis the current systemUiVisibility to apply. + * @param color the current color to apply. + * @param size the current size in the non-parent-matching dimension. + * @param verticalBar if true the view is attached to a vertical edge, otherwise to a + * horizontal edge, + * @param animate if true, the change will be animated. + */ private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color, - int height, boolean animate) { - boolean show = height > 0 && (sysUiVis & state.systemUiHideFlag) == 0 + int size, boolean verticalBar, boolean animate) { + boolean show = size > 0 && (sysUiVis & state.systemUiHideFlag) == 0 && (getAttributes().flags & state.hideWindowFlag) == 0 && (getAttributes().flags & state.translucentFlag) == 0 && (color & Color.BLACK) != 0 @@ -2935,6 +2966,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { boolean visibilityChanged = false; View view = state.view; + int resolvedHeight = verticalBar ? LayoutParams.MATCH_PARENT : size; + int resolvedWidth = verticalBar ? size : LayoutParams.MATCH_PARENT; + int resolvedGravity = verticalBar ? state.horizontalGravity : state.verticalGravity; + if (view == null) { if (show) { state.view = view = new View(mContext); @@ -2945,8 +2980,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { view.setVisibility(INVISIBLE); state.targetVisibility = VISIBLE; - addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, height, - Gravity.START | state.verticalGravity)); + addView(view, new LayoutParams(resolvedWidth, resolvedHeight, resolvedGravity)); updateColorViewTranslations(); } } else { @@ -2955,8 +2989,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { state.targetVisibility = vis; if (show) { LayoutParams lp = (LayoutParams) view.getLayoutParams(); - if (lp.height != height) { - lp.height = height; + if (lp.height != resolvedHeight || lp.width != resolvedWidth + || lp.gravity != resolvedGravity) { + lp.height = resolvedHeight; + lp.width = resolvedWidth; + lp.gravity = resolvedGravity; view.setLayoutParams(lp); } view.setBackgroundColor(color); @@ -3583,19 +3620,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { requestFeature(FEATURE_ACTIVITY_TRANSITIONS); } - final WindowManager windowService = (WindowManager) getContext().getSystemService( - Context.WINDOW_SERVICE); - if (windowService != null) { - final Display display = windowService.getDefaultDisplay(); - final boolean shouldUseBottomOutset = - display.getDisplayId() == Display.DEFAULT_DISPLAY - || (getForcedWindowFlags() & FLAG_FULLSCREEN) != 0; - if (shouldUseBottomOutset) { - mOutsetBottomPx = ScreenShapeHelper.getWindowOutsetBottomPx( - getContext().getResources().getDisplayMetrics(), a); - } - } - final Context context = getContext(); final int targetSdk = context.getApplicationInfo().targetSdkVersion; final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB; @@ -3870,7 +3894,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // A pending invalidation will typically be resolved before the posted message // would run normally in order to satisfy instance state restoration. PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false); - if (!isDestroyed() && (st == null || st.menu == null)) { + if (!isDestroyed() && (st == null || st.menu == null) && !mIsStartingWindow) { invalidatePanelMenu(FEATURE_ACTION_BAR); } } else { @@ -4296,8 +4320,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (!result && (getContext().getResources().getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION) { // On TVs, if the app doesn't implement search, we want to launch assist. + Bundle args = new Bundle(); + args.putInt(Intent.EXTRA_ASSIST_INPUT_DEVICE_ID, event.getDeviceId()); return ((SearchManager)getContext().getSystemService(Context.SEARCH_SERVICE)) - .launchAssistAction(null, UserHandle.myUserId()); + .launchAssistAction(null, UserHandle.myUserId(), args); } return result; } @@ -4884,16 +4910,18 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { final int systemUiHideFlag; final int translucentFlag; final int verticalGravity; + final int horizontalGravity; final String transitionName; final int hideWindowFlag; ColorViewState(int systemUiHideFlag, - int translucentFlag, int verticalGravity, + int translucentFlag, int verticalGravity, int horizontalGravity, String transitionName, int id, int hideWindowFlag) { this.id = id; this.systemUiHideFlag = systemUiHideFlag; this.translucentFlag = translucentFlag; this.verticalGravity = verticalGravity; + this.horizontalGravity = horizontalGravity; this.transitionName = transitionName; this.hideWindowFlag = hideWindowFlag; } @@ -4943,4 +4971,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mDecor.updateColorViews(null, false /* animate */); } } + + public void setIsStartingWindow(boolean isStartingWindow) { + mIsStartingWindow = isStartingWindow; + } } diff --git a/core/java/com/android/internal/util/ScreenShapeHelper.java b/core/java/com/android/internal/util/ScreenShapeHelper.java index 58ae853..4a196f8 100644 --- a/core/java/com/android/internal/util/ScreenShapeHelper.java +++ b/core/java/com/android/internal/util/ScreenShapeHelper.java @@ -18,19 +18,13 @@ public class ScreenShapeHelper { /** * Return the bottom pixel window outset of a window given its style attributes. - * @param displayMetrics Display metrics of the current device - * @param windowStyle Window style attributes for the window. * @return An outset dimension in pixels or 0 if no outset should be applied. */ - public static int getWindowOutsetBottomPx(DisplayMetrics displayMetrics, - TypedArray windowStyle) { + public static int getWindowOutsetBottomPx(Resources resources) { if (IS_EMULATOR) { return SystemProperties.getInt(ViewRootImpl.PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX, 0); - } else if (windowStyle.hasValue(R.styleable.Window_windowOutsetBottom)) { - TypedValue outsetBottom = new TypedValue(); - windowStyle.getValue(R.styleable.Window_windowOutsetBottom, outsetBottom); - return (int) outsetBottom.getDimension(displayMetrics); + } else { + return resources.getInteger(com.android.internal.R.integer.config_windowOutsetBottom); } - return 0; } } diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java index e27ba13..3eeabcd 100644 --- a/core/java/com/android/internal/view/BaseIWindow.java +++ b/core/java/com/android/internal/view/BaseIWindow.java @@ -34,8 +34,8 @@ public class BaseIWindow extends IWindow.Stub { } @Override - public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, - Rect visibleInsets, Rect stableInsets, boolean reportDraw, Configuration newConfig) { + public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets, + Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig) { if (reportDraw) { try { mSession.finishDrawing(this); diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java index 93d2a1d..661dce1 100644 --- a/core/java/com/android/internal/view/FloatingActionMode.java +++ b/core/java/com/android/internal/view/FloatingActionMode.java @@ -23,6 +23,7 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import android.view.ViewConfiguration; import com.android.internal.util.Preconditions; import com.android.internal.view.menu.MenuBuilder; @@ -30,7 +31,7 @@ import com.android.internal.widget.FloatingToolbar; public class FloatingActionMode extends ActionMode { - private static final int MAX_SNOOZE_TIME = 3000; + private static final int MAX_HIDE_DURATION = 3000; private static final int MOVING_HIDE_DELAY = 300; private final Context mContext; @@ -50,9 +51,9 @@ public class FloatingActionMode extends ActionMode { } }; - private final Runnable mSnoozeOff = new Runnable() { + private final Runnable mHideOff = new Runnable() { public void run() { - mFloatingToolbarVisibilityHelper.setSnoozed(false); + mFloatingToolbarVisibilityHelper.setHideRequested(false); } }; @@ -127,11 +128,16 @@ public class FloatingActionMode extends ActionMode { private void repositionToolbar() { checkToolbarInitialized(); + + mContentRectOnWindow.set(mContentRect); + mContentRectOnWindow.offset(mViewPosition[0], mViewPosition[1]); + // Make sure that content rect is not out of the view's visible bounds. mContentRectOnWindow.set( - mContentRect.left + mViewPosition[0], - mContentRect.top + mViewPosition[1], - mContentRect.right + mViewPosition[0], - mContentRect.bottom + mViewPosition[1]); + Math.max(mContentRectOnWindow.left, mViewRect.left), + Math.max(mContentRectOnWindow.top, mViewRect.top), + Math.min(mContentRectOnWindow.right, mViewRect.right), + Math.min(mContentRectOnWindow.bottom, mViewRect.bottom)); + if (!mContentRectOnWindow.equals(mPreviousContentRectOnWindow)) { if (!mPreviousContentRectOnWindow.isEmpty()) { notifyContentRectMoving(); @@ -166,15 +172,19 @@ public class FloatingActionMode extends ActionMode { } @Override - public void snooze(int snoozeTime) { + public void hide(long duration) { checkToolbarInitialized(); - snoozeTime = Math.min(MAX_SNOOZE_TIME, snoozeTime); - mOriginatingView.removeCallbacks(mSnoozeOff); - if (snoozeTime <= 0) { - mSnoozeOff.run(); + + if (duration == ActionMode.DEFAULT_HIDE_DURATION) { + duration = ViewConfiguration.getDefaultActionModeHideDuration(); + } + duration = Math.min(MAX_HIDE_DURATION, duration); + mOriginatingView.removeCallbacks(mHideOff); + if (duration <= 0) { + mHideOff.run(); } else { - mFloatingToolbarVisibilityHelper.setSnoozed(true); - mOriginatingView.postDelayed(mSnoozeOff, snoozeTime); + mFloatingToolbarVisibilityHelper.setHideRequested(true); + mOriginatingView.postDelayed(mHideOff, duration); } } @@ -220,7 +230,7 @@ public class FloatingActionMode extends ActionMode { private void reset() { mOriginatingView.removeCallbacks(mMovingOff); - mOriginatingView.removeCallbacks(mSnoozeOff); + mOriginatingView.removeCallbacks(mHideOff); } @@ -231,7 +241,7 @@ public class FloatingActionMode extends ActionMode { private final FloatingToolbar mToolbar; - private boolean mSnoozed; + private boolean mHideRequested; private boolean mMoving; private boolean mOutOfBounds; @@ -239,8 +249,8 @@ public class FloatingActionMode extends ActionMode { mToolbar = Preconditions.checkNotNull(toolbar); } - public void setSnoozed(boolean snoozed) { - mSnoozed = snoozed; + public void setHideRequested(boolean hide) { + mHideRequested = hide; updateToolbarVisibility(); } @@ -255,7 +265,7 @@ public class FloatingActionMode extends ActionMode { } private void updateToolbarVisibility() { - if (mSnoozed || mMoving || mOutOfBounds) { + if (mHideRequested || mMoving || mOutOfBounds) { mToolbar.hide(); } else if (mToolbar.isHidden()) { mToolbar.show(); diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index 3cff59a..c77d614 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -37,6 +37,7 @@ import android.view.View.MeasureSpec; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.Window; +import android.view.WindowInsets; import android.view.WindowManager; import android.view.animation.Animation; import android.view.animation.AnimationSet; @@ -83,7 +84,7 @@ public final class FloatingToolbar { private final Rect mContentRect = new Rect(); private Menu mMenu; - private List<CharSequence> mShowingTitles = new ArrayList<CharSequence>(); + private List<Object> mShowingMenuItems = new ArrayList<Object>(); private MenuItem.OnMenuItemClickListener mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER; private int mSuggestedWidth; @@ -155,7 +156,7 @@ public final class FloatingToolbar { if (!isCurrentlyShowing(menuItems) || mWidthChanged) { mPopup.dismiss(); mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth); - mShowingTitles = getMenuItemTitles(menuItems); + mShowingMenuItems = getShowingMenuItemsReferences(menuItems); } mPopup.updateCoordinates(mContentRect); if (!mPopup.isShowing()) { @@ -210,7 +211,7 @@ public final class FloatingToolbar { * Returns true if this floating toolbar is currently showing the specified menu items. */ private boolean isCurrentlyShowing(List<MenuItem> menuItems) { - return mShowingTitles.equals(getMenuItemTitles(menuItems)); + return mShowingMenuItems.equals(getShowingMenuItemsReferences(menuItems)); } /** @@ -233,12 +234,16 @@ public final class FloatingToolbar { return menuItems; } - private List<CharSequence> getMenuItemTitles(List<MenuItem> menuItems) { - List<CharSequence> titles = new ArrayList<CharSequence>(); + private List<Object> getShowingMenuItemsReferences(List<MenuItem> menuItems) { + List<Object> references = new ArrayList<Object>(); for (MenuItem menuItem : menuItems) { - titles.add(menuItem.getTitle()); + if (isIconOnlyMenuItem(menuItem)) { + references.add(menuItem.getIcon()); + } else { + references.add(menuItem.getTitle()); + } } - return titles; + return references; } @@ -289,7 +294,6 @@ public final class FloatingToolbar { public void onAnimationRepeat(Animation animation) { } }; - private final AnimatorSet mShowAnimation; private final AnimatorSet mDismissAnimation; private final AnimatorSet mHideAnimation; private final AnimationSet mOpenOverflowAnimation = new AnimationSet(true) { @@ -324,6 +328,7 @@ public final class FloatingToolbar { } }; + private final Rect mViewPort = new Rect(); private final Point mCoords = new Point(); private final Region mTouchableRegion = new Region(); @@ -356,7 +361,6 @@ public final class FloatingToolbar { mParent = Preconditions.checkNotNull(parent); mContentContainer = createContentContainer(parent.getContext()); mPopupWindow = createPopupWindow(mContentContainer); - mShowAnimation = createGrowFadeInFromBottom(mContentContainer); mDismissAnimation = createShrinkFadeOutFromBottomAnimation( mContentContainer, 150, // startDelay @@ -385,8 +389,10 @@ public final class FloatingToolbar { /** * Lays out buttons for the specified menu items. */ - public void layoutMenuItems(List<MenuItem> menuItems, - MenuItem.OnMenuItemClickListener menuItemClickListener, int suggestedWidth) { + public void layoutMenuItems( + List<MenuItem> menuItems, + MenuItem.OnMenuItemClickListener menuItemClickListener, + int suggestedWidth) { Preconditions.checkNotNull(menuItems); mContentContainer.removeAllViews(); @@ -394,7 +400,7 @@ public final class FloatingToolbar { mMainPanel = new FloatingToolbarMainPanel(mParent.getContext(), mOpenOverflow); } List<MenuItem> overflowMenuItems = - mMainPanel.layoutMenuItems(menuItems, suggestedWidth); + mMainPanel.layoutMenuItems(menuItems, getToolbarWidth(suggestedWidth)); mMainPanel.setOnMenuItemClickListener(menuItemClickListener); if (!overflowMenuItems.isEmpty()) { if (mOverflowPanel == null) { @@ -430,7 +436,8 @@ public final class FloatingToolbar { // The "show" animation will make this visible. mContentContainer.setAlpha(0); } - updateOverflowHeight(contentRect.top - (mMarginVertical * 2)); + refreshViewPort(); + updateOverflowHeight(contentRect.top - (mMarginVertical * 2) - mViewPort.top); refreshCoordinatesAndOverflowDirection(contentRect); preparePopupContent(); mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, mCoords.x, mCoords.y); @@ -494,6 +501,7 @@ public final class FloatingToolbar { } cancelOverflowAnimations(); + refreshViewPort(); refreshCoordinatesAndOverflowDirection(contentRect); preparePopupContent(); mPopupWindow.update(mCoords.x, mCoords.y, getWidth(), getHeight()); @@ -521,18 +529,24 @@ public final class FloatingToolbar { } private void refreshCoordinatesAndOverflowDirection(Rect contentRect) { + // NOTE: Ensure that mViewPort has been refreshed before this. + int x = contentRect.centerX() - getWidth() / 2; int y; - if (contentRect.top > getHeight()) { + if (contentRect.top - getHeight() > mViewPort.top) { y = contentRect.top - getHeight(); mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_UP; - } else if (contentRect.top > getToolbarHeightWithVerticalMargin()) { + } else if (contentRect.top - getToolbarHeightWithVerticalMargin() > mViewPort.top) { y = contentRect.top - getToolbarHeightWithVerticalMargin(); mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN; } else { y = contentRect.bottom; mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN; } + + // Update x so that the toolbar isn't rendered behind the nav bar in landscape. + x = Math.max(0, Math.min(x, mViewPort.right - getWidth())); + mCoords.set(x, y); if (mOverflowPanel != null) { mOverflowPanel.setOverflowDirection(mOverflowDirection); @@ -547,7 +561,7 @@ public final class FloatingToolbar { * Performs the "show" animation on the floating popup. */ private void runShowAnimation() { - mShowAnimation.start(); + createGrowFadeInFromBottom(mContentContainer).start(); } /** @@ -593,7 +607,8 @@ public final class FloatingToolbar { final int startWidth = mContentContainer.getWidth(); final int startHeight = mContentContainer.getHeight(); final float startY = mContentContainer.getY(); - final float right = mContentContainer.getX() + mContentContainer.getWidth(); + final float left = mContentContainer.getX(); + final float right = left + mContentContainer.getWidth(); Animation widthAnimation = new Animation() { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { @@ -601,7 +616,11 @@ public final class FloatingToolbar { int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth)); params.width = startWidth + deltaWidth; mContentContainer.setLayoutParams(params); - mContentContainer.setX(right - mContentContainer.getWidth()); + if (isRTL()) { + mContentContainer.setX(left); + } else { + mContentContainer.setX(right - mContentContainer.getWidth()); + } } }; Animation heightAnimation = new Animation() { @@ -644,9 +663,10 @@ public final class FloatingToolbar { final int targetHeight = mainPanelSize.getHeight(); final int startWidth = mContentContainer.getWidth(); final int startHeight = mContentContainer.getHeight(); - final float right = mContentContainer.getX() + mContentContainer.getWidth(); final float bottom = mContentContainer.getY() + mContentContainer.getHeight(); final boolean morphedUpwards = (mOverflowDirection == OVERFLOW_DIRECTION_UP); + final float left = mContentContainer.getX(); + final float right = left + mContentContainer.getWidth(); Animation widthAnimation = new Animation() { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { @@ -654,7 +674,11 @@ public final class FloatingToolbar { int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth)); params.width = startWidth + deltaWidth; mContentContainer.setLayoutParams(params); - mContentContainer.setX(right - mContentContainer.getWidth()); + if (isRTL()) { + mContentContainer.setX(left); + } else { + mContentContainer.setX(right - mContentContainer.getWidth()); + } } }; Animation heightAnimation = new Animation() { @@ -747,9 +771,7 @@ public final class FloatingToolbar { */ private void positionMainPanel() { Preconditions.checkNotNull(mMainPanel); - float x = mPopupWindow.getWidth() - - (mMainPanel.getView().getMeasuredWidth() + mMarginHorizontal); - mContentContainer.setX(x); + mContentContainer.setX(mMarginHorizontal); float y = mMarginVertical; if (mOverflowDirection == OVERFLOW_DIRECTION_UP) { @@ -765,8 +787,13 @@ public final class FloatingToolbar { */ private void positionOverflowPanel() { Preconditions.checkNotNull(mOverflowPanel); - float x = mPopupWindow.getWidth() + float x; + if (isRTL()) { + x = mMarginHorizontal; + } else { + x = mPopupWindow.getWidth() - (mOverflowPanel.getView().getMeasuredWidth() + mMarginHorizontal); + } mContentContainer.setX(x); mContentContainer.setY(mMarginVertical); setContentAreaAsTouchableSurface(); @@ -808,6 +835,29 @@ public final class FloatingToolbar { mPopupWindow.setHeight(height + mMarginVertical * 2); } + + private void refreshViewPort() { + mParent.getGlobalVisibleRect(mViewPort); + WindowInsets windowInsets = mParent.getRootWindowInsets(); + mViewPort.set( + mViewPort.left + windowInsets.getStableInsetLeft(), + mViewPort.top + windowInsets.getStableInsetTop(), + mViewPort.right - windowInsets.getStableInsetRight(), + mViewPort.bottom - windowInsets.getStableInsetBottom()); + } + + private int getToolbarWidth(int suggestedWidth) { + int width = suggestedWidth; + refreshViewPort(); + int maximumWidth = mViewPort.width() - 2 * mParent.getResources() + .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin); + if (width <= 0) { + width = mParent.getResources() + .getDimensionPixelSize(R.dimen.floating_toolbar_preferred_width); + } + return Math.min(width, maximumWidth); + } + /** * Sets the touchable region of this popup to be zero. This means that all touch events on * this popup will go through to the surface behind it. @@ -844,6 +894,10 @@ public final class FloatingToolbar { viewTreeObserver.removeOnComputeInternalInsetsListener(mInsetsComputer); viewTreeObserver.addOnComputeInternalInsetsListener(mInsetsComputer); } + + private boolean isRTL() { + return mContentContainer.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + } } /** @@ -889,12 +943,11 @@ public final class FloatingToolbar { * * @return The menu items that are not included in this main panel. */ - public List<MenuItem> layoutMenuItems(List<MenuItem> menuItems, int suggestedWidth) { + public List<MenuItem> layoutMenuItems(List<MenuItem> menuItems, int width) { Preconditions.checkNotNull(menuItems); - final int toolbarWidth = getAdjustedToolbarWidth(mContext, suggestedWidth) - // Reserve space for the "open overflow" button. - - getEstimatedOpenOverflowButtonWidth(mContext); + // Reserve space for the "open overflow" button. + final int toolbarWidth = width - getEstimatedOpenOverflowButtonWidth(mContext); int availableWidth = toolbarWidth; final LinkedList<MenuItem> remainingMenuItems = new LinkedList<MenuItem>(menuItems); @@ -1325,7 +1378,9 @@ public final class FloatingToolbar { growFadeInFromBottomAnimation.playTogether( ObjectAnimator.ofFloat(view, View.SCALE_X, 0.5f, 1).setDuration(125), ObjectAnimator.ofFloat(view, View.SCALE_Y, 0.5f, 1).setDuration(125), - ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(75)); + ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(75), + // Make sure that view.x is always fixed throughout the duration of this animation. + ObjectAnimator.ofFloat(view, View.X, view.getX(), view.getX())); growFadeInFromBottomAnimation.setStartDelay(50); return growFadeInFromBottomAnimation; } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index aee0ff6..86d11be 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -841,7 +841,7 @@ public class LockPatternUtils { final byte[] bytes = string.getBytes(); for (int i = 0; i < bytes.length; i++) { - byte b = bytes[i]; + byte b = (byte) (bytes[i] - '1'); result.add(LockPatternView.Cell.of(b / 3, b % 3)); } return result; @@ -861,7 +861,21 @@ public class LockPatternUtils { byte[] res = new byte[patternSize]; for (int i = 0; i < patternSize; i++) { LockPatternView.Cell cell = pattern.get(i); - res[i] = (byte) (cell.getRow() * 3 + cell.getColumn()); + res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1'); + } + return new String(res); + } + + public static String patternStringToBaseZero(String pattern) { + if (pattern == null) { + return ""; + } + final int patternSize = pattern.length(); + + byte[] res = new byte[patternSize]; + final byte[] bytes = pattern.getBytes(); + for (int i = 0; i < patternSize; i++) { + res[i] = (byte) (bytes[i] - '1'); } return new String(res); } diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java index 6d4e058..35ed63b 100644 --- a/core/java/com/android/internal/widget/SwipeDismissLayout.java +++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java @@ -16,9 +16,11 @@ package com.android.internal.widget; -import android.animation.TimeInterpolator; import android.app.Activity; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.Log; @@ -28,8 +30,6 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewTreeObserver; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; /** @@ -62,10 +62,6 @@ public class SwipeDismissLayout extends FrameLayout { // Cached ViewConfiguration and system-wide constant values private int mSlop; private int mMinFlingVelocity; - private int mMaxFlingVelocity; - private long mAnimationTime; - private TimeInterpolator mCancelInterpolator; - private TimeInterpolator mDismissInterpolator; // Transient properties private int mActiveTouchId; @@ -92,6 +88,18 @@ public class SwipeDismissLayout extends FrameLayout { } } }; + private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (mDismissed) { + dismiss(); + } else { + cancel(); + } + resetMembers(); + } + }; + private IntentFilter mScreenOffFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF); private float mLastX; @@ -114,11 +122,6 @@ public class SwipeDismissLayout extends FrameLayout { ViewConfiguration vc = ViewConfiguration.get(context); mSlop = vc.getScaledTouchSlop(); mMinFlingVelocity = vc.getScaledMinimumFlingVelocity(); - mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity(); - mAnimationTime = getContext().getResources().getInteger( - android.R.integer.config_shortAnimTime); - mCancelInterpolator = new DecelerateInterpolator(1.5f); - mDismissInterpolator = new AccelerateInterpolator(1.5f); TypedArray a = context.getTheme().obtainStyledAttributes( com.android.internal.R.styleable.Theme); mUseDynamicTranslucency = !a.hasValue( @@ -141,15 +144,17 @@ public class SwipeDismissLayout extends FrameLayout { getViewTreeObserver().addOnEnterAnimationCompleteListener( mOnEnterAnimationCompleteListener); } + getContext().registerReceiver(mScreenOffReceiver, mScreenOffFilter); } @Override protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); + getContext().unregisterReceiver(mScreenOffReceiver); if (getContext() instanceof Activity) { getViewTreeObserver().removeOnEnterAnimationCompleteListener( mOnEnterAnimationCompleteListener); } + super.onDetachedFromWindow(); } @Override |