Merge "Add a security warning to PdfRenderer doc." into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 4dfbe63..6fdd1bc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2699,7 +2699,7 @@
method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, android.os.Handler);
method public float getCenterX();
method public float getCenterY();
- method public android.graphics.Region getMagnifiedRegion();
+ method public android.graphics.Region getMagnificationRegion();
method public float getScale();
method public boolean removeListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener);
method public boolean reset(boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index 3344b52..41b73eb 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2810,7 +2810,7 @@
method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, android.os.Handler);
method public float getCenterX();
method public float getCenterY();
- method public android.graphics.Region getMagnifiedRegion();
+ method public android.graphics.Region getMagnificationRegion();
method public float getScale();
method public boolean removeListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener);
method public boolean reset(boolean);
diff --git a/api/test-current.txt b/api/test-current.txt
index a0ca0f4..d40d0b8 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2699,7 +2699,7 @@
method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, android.os.Handler);
method public float getCenterX();
method public float getCenterY();
- method public android.graphics.Region getMagnifiedRegion();
+ method public android.graphics.Region getMagnificationRegion();
method public float getScale();
method public boolean removeListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener);
method public boolean reset(boolean);
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index 3ae9e12..fae0400 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -53,7 +53,6 @@
libutils \
liblog \
libbinder \
- libnativeloader \
libandroid_runtime \
$(app_process_common_shared_libs) \
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 7590325..2e02382 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -21,7 +21,6 @@
#include <cutils/properties.h>
#include <cutils/trace.h>
#include <android_runtime/AndroidRuntime.h>
-#include <nativeloader/native_loader.h>
#include <private/android_filesystem_config.h> // for AID_SYSTEM
namespace android {
@@ -305,7 +304,6 @@
}
if (zygote) {
- InitializeNativeLoader();
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 56728ad..8b277b2 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -925,18 +925,25 @@
}
/**
- * Returns the region of the screen currently being magnified. If
- * magnification is not enabled, the returned region will be empty.
+ * Returns the region of the screen currently active for magnification. Changes to
+ * magnification scale and center only affect this portion of the screen. The rest of the
+ * screen, for example input methods, cannot be magnified. This region is relative to the
+ * unscaled screen and is independent of the scale and center point.
+ * <p>
+ * The returned region will be empty if magnification is not active. Magnification is active
+ * if magnification gestures are enabled or if a service is running that can control
+ * magnification.
* <p>
* <strong>Note:</strong> If the service is not yet connected (e.g.
* {@link AccessibilityService#onServiceConnected()} has not yet been
* called) or the service has been disconnected, this method will
* return an empty region.
*
- * @return the screen-relative bounds of the magnified region
+ * @return the region of the screen currently active for magnification, or an empty region
+ * if magnification is not active.
*/
@NonNull
- public Region getMagnifiedRegion() {
+ public Region getMagnificationRegion() {
final IAccessibilityServiceConnection connection =
AccessibilityInteractionClient.getInstance().getConnection(
mService.mConnectionId);
@@ -1049,11 +1056,12 @@
* Called when the magnified region, scale, or center changes.
*
* @param controller the magnification controller
- * @param region the new magnified region, may be empty if
- * magnification is not enabled (e.g. scale is 1)
+ * @param region the magnification region
* @param scale the new scale
- * @param centerX the new X coordinate around which magnification is focused
- * @param centerY the new Y coordinate around which magnification is focused
+ * @param centerX the new X coordinate, in unscaled coordinates, around which
+ * magnification is focused
+ * @param centerY the new Y coordinate, in unscaled coordinates, around which
+ * magnification is focused
*/
void onMagnificationChanged(@NonNull MagnificationController controller,
@NonNull Region region, float scale, float centerX, float centerY);
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
index e18a34d..fc9581e 100644
--- a/core/java/android/accessibilityservice/GestureDescription.java
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -18,7 +18,6 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
-import android.graphics.Matrix;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
@@ -26,10 +25,8 @@
import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
import android.view.MotionEvent.PointerProperties;
-import android.view.ViewConfiguration;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
/**
@@ -160,9 +157,10 @@
private final List<StrokeDescription> mStrokes = new ArrayList<>();
/**
- * Add a stroke to the gesture description. Up to {@code MAX_STROKE_COUNT} paths may be
- * added to a gesture, and the total gesture duration (earliest path start time to latest path
- * end time) may not exceed {@code MAX_GESTURE_DURATION_MS}.
+ * Add a stroke to the gesture description. Up to
+ * {@link GestureDescription#getMaxStrokeCount()} paths may be
+ * added to a gesture, and the total gesture duration (earliest path start time to latest
+ * path end time) may not exceed {@link GestureDescription#getMaxGestureDuration()}.
*
* @param strokeDescription the stroke to add.
*
@@ -201,10 +199,13 @@
long mEndTime;
private float mTimeToLengthConversion;
private PathMeasure mPathMeasure;
+ // The tap location is only set for zero-length paths
+ float[] mTapLocation;
/**
- * @param path The path to follow. Must have exactly one contour, and that contour must
- * have nonzero length. The bounds of the path must not be negative.
+ * @param path The path to follow. Must have exactly one contour. The bounds of the path
+ * must not be negative. The path must not be empty. If the path has zero length
+ * (for example, a single {@code moveTo()}), the stroke is a touch that doesn't move.
* @param startTime The time, in milliseconds, from the time the gesture starts to the
* time the stroke should start. Must not be negative.
* @param duration The duration, in milliseconds, the stroke takes to traverse the path.
@@ -225,10 +226,18 @@
|| (bounds.left < 0)) {
throw new IllegalArgumentException("Path bounds must not be negative");
}
+ if (path.isEmpty()) {
+ throw new IllegalArgumentException("Path is empty");
+ }
mPath = new Path(path);
mPathMeasure = new PathMeasure(path, false);
if (mPathMeasure.getLength() == 0) {
- throw new IllegalArgumentException("Path has zero length");
+ // Treat zero-length paths as taps
+ Path tempPath = new Path(path);
+ tempPath.lineTo(-1, -1);
+ mTapLocation = new float[2];
+ PathMeasure pathMeasure = new PathMeasure(tempPath, false);
+ pathMeasure.getPosTan(0, mTapLocation, null);
}
if (mPathMeasure.nextContour()) {
throw new IllegalArgumentException("Path has more than one contour");
@@ -237,12 +246,10 @@
* Calling nextContour has moved mPathMeasure off the first contour, which is the only
* one we care about. Set the path again to go back to the first contour.
*/
- mPathMeasure.setPath(path, false);
+ mPathMeasure.setPath(mPath, false);
mStartTime = startTime;
mEndTime = startTime + duration;
- if (duration > 0) {
- mTimeToLengthConversion = getLength() / duration;
- }
+ mTimeToLengthConversion = getLength() / duration;
}
/**
@@ -278,6 +285,11 @@
/* Assumes hasPointForTime returns true */
boolean getPosForTime(long time, float[] pos) {
+ if (mTapLocation != null) {
+ pos[0] = mTapLocation[0];
+ pos[1] = mTapLocation[1];
+ return true;
+ }
if (time == mEndTime) {
// Close to the end time, roundoff can be a problem
return mPathMeasure.getPosTan(getLength(), pos, null);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 0764ff4..f7c0b4c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3479,7 +3479,9 @@
// the decor view we have to notify the view root that the
// callbacks may have changed.
ViewRootImpl impl = decor.getViewRootImpl();
- impl.notifyChildRebuilt();
+ if (impl != null) {
+ impl.notifyChildRebuilt();
+ }
}
if (a.mVisibleFromClient && !a.mWindowAdded) {
a.mWindowAdded = true;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index d7705b9..2a3e3d8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3351,7 +3351,8 @@
}
private void resetStandardTemplateWithActions(RemoteViews big) {
- big.setViewVisibility(R.id.actions_container, View.GONE);
+ // actions_container is only reset when there are no actions to avoid focus issues with
+ // remote inputs.
big.setViewVisibility(R.id.actions, View.GONE);
big.removeAllViews(R.id.actions);
@@ -3396,6 +3397,8 @@
}
big.addView(R.id.actions, button);
}
+ } else {
+ big.setViewVisibility(R.id.actions_container, View.GONE);
}
CharSequence[] replyText = mN.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY);
@@ -4265,15 +4268,19 @@
public RemoteViews makeBigContentView() {
// Nasty
- CharSequence oldBuilderContentText =
- mBuilder.getAllExtras().getCharSequence(EXTRA_TEXT);
+ CharSequence text = mBuilder.getAllExtras().getCharSequence(EXTRA_TEXT);
mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, null);
RemoteViews contentView = getStandardView(mBuilder.getBigTextLayoutResource());
- mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, oldBuilderContentText);
+ mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, text);
CharSequence bigTextText = mBuilder.processLegacyText(mBigText);
+ if (TextUtils.isEmpty(bigTextText)) {
+ // In case the bigtext is null / empty fall back to the normal text to avoid a weird
+ // experience
+ bigTextText = mBuilder.processLegacyText(text);
+ }
contentView.setTextViewText(R.id.big_text, bigTextText);
contentView.setViewVisibility(R.id.big_text,
TextUtils.isEmpty(bigTextText) ? View.GONE : View.VISIBLE);
@@ -4461,8 +4468,8 @@
mAllowGeneratedReplies = extras.getBoolean(EXTRA_ALLOW_GENERATED_REPLIES,
mAllowGeneratedReplies);
Parcelable[] parcelables = extras.getParcelableArray(EXTRA_MESSAGES);
- if (parcelables != null && parcelables instanceof Bundle[]) {
- mMessages = Message.getMessagesFromBundleArray((Bundle[]) parcelables);
+ if (parcelables != null && parcelables instanceof Parcelable[]) {
+ mMessages = Message.getMessagesFromBundleArray(parcelables);
}
}
@@ -4558,6 +4565,25 @@
return sb;
}
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeHeadsUpContentView() {
+ Message m = findLatestIncomingMessage();
+ CharSequence title = mConversationTitle != null
+ ? mConversationTitle
+ : (m == null) ? null : m.mSender;
+ CharSequence text = (m == null)
+ ? null
+ : mConversationTitle != null ? makeMessageLine(m) : m.mText;
+
+ return mBuilder.applyStandardTemplateWithActions(mBuilder.getBigBaseLayoutResource(),
+ false /* hasProgress */,
+ title,
+ text);
+ }
+
private static TextAppearanceSpan makeFontColorSpan(int color) {
return new TextAppearanceSpan(null, 0, 0,
ColorStateList.valueOf(color), null);
@@ -4691,12 +4717,14 @@
return bundles;
}
- static List<Message> getMessagesFromBundleArray(Bundle[] bundles) {
+ static List<Message> getMessagesFromBundleArray(Parcelable[] bundles) {
List<Message> messages = new ArrayList<>(bundles.length);
for (int i = 0; i < bundles.length; i++) {
- Message message = getMessageFromBundle(bundles[i]);
- if (message != null) {
- messages.add(message);
+ if (bundles[i] instanceof Bundle) {
+ Message message = getMessageFromBundle((Bundle)bundles[i]);
+ if (message != null) {
+ messages.add(message);
+ }
}
}
return messages;
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index e9d82af..c5e0ea7 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -484,7 +484,7 @@
*/
public void rollbackContentChanged() {
if (mProcessingChange) {
- mContentChanged = true;
+ onContentChanged();
}
}
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index a57fac3..2b8b28d 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -52,6 +52,9 @@
void setRestrictBackground(boolean restrictBackground);
boolean getRestrictBackground();
+ /** Callback used to change internal state on tethering */
+ void onTetheringChanged(String iface, boolean tethering);
+
/** Control which applications can be exempt from background data restrictions */
void addRestrictBackgroundWhitelistedUid(int uid);
void removeRestrictBackgroundWhitelistedUid(int uid);
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b9a3cff..2c63be2 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1070,6 +1070,9 @@
public int statSoftIrqTime;
public int statIdlTime;
+ // Platform-level low power state stats
+ public String statPlatformIdleState;
+
public HistoryStepDetails() {
clear();
}
@@ -1099,6 +1102,7 @@
out.writeInt(statIrqTime);
out.writeInt(statSoftIrqTime);
out.writeInt(statIdlTime);
+ out.writeString(statPlatformIdleState);
}
public void readFromParcel(Parcel in) {
@@ -1119,6 +1123,7 @@
statIrqTime = in.readInt();
statSoftIrqTime = in.readInt();
statIdlTime = in.readInt();
+ statPlatformIdleState = in.readString();
}
}
@@ -4788,6 +4793,8 @@
pw.print(sb);
pw.print(")");
}
+ pw.print(", PlatformIdleStat ");
+ pw.print(rec.stepDetails.statPlatformIdleState);
pw.println();
} else {
pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
@@ -4821,6 +4828,8 @@
pw.print(rec.stepDetails.statSoftIrqTime);
pw.print(',');
pw.print(rec.stepDetails.statIdlTime);
+ pw.print(',');
+ pw.print(rec.stepDetails.statPlatformIdleState);
pw.println();
}
}
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index 3ad730b..4b188c4 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -54,13 +54,12 @@
public interface MagnificationCallbacks {
/**
- * Called when the bounds of the screen content that is magnified changed.
- * Note that not the entire screen is magnified.
+ * Called when the region where magnification operates changes. Note that this isn't the
+ * entire screen. For example, IMEs are not magnified.
*
- * @param magnifiedBounds the currently magnified region
- * @param availableBounds the region available for magnification
+ * @param magnificationRegion the current magnification region
*/
- public void onMagnifiedBoundsChanged(Region magnifiedBounds, Region availableBounds);
+ public void onMagnificationRegionChanged(Region magnificationRegion);
/**
* Called when an application requests a rectangle on the screen to allow
@@ -158,13 +157,11 @@
public abstract void setMagnificationSpec(MagnificationSpec spec);
/**
- * Obtains the magnified and available regions.
+ * Obtains the magnification regions.
*
- * @param outMagnified the currently magnified region
- * @param outAvailable the region available for magnification
+ * @param magnificationRegion the current magnification region
*/
- public abstract void getMagnificationRegions(@NonNull Region outMagnified,
- @NonNull Region outAvailable);
+ public abstract void getMagnificationRegion(@NonNull Region magnificationRegion);
/**
* Gets the magnification and translation applied to a window given its token.
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index bfc87f2..bb1ffcb 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1308,7 +1308,7 @@
// Include the padding of the list
int returnedHeight = mListPadding.top + mListPadding.bottom;
- final int dividerHeight = ((mDividerHeight > 0) && mDivider != null) ? mDividerHeight : 0;
+ final int dividerHeight = mDividerHeight;
// The previous height value that was less than maxHeight and contained
// no partial children
int prevHeightWithoutPartialChild = 0;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index e69ed35..5358d78 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -108,7 +108,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 142 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 143 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -150,6 +150,13 @@
public void batterySendBroadcast(Intent intent);
}
+ public interface PlatformIdleStateCallback {
+ public String getPlatformLowPowerStats();
+ }
+
+ private final PlatformIdleStateCallback mPlatformIdleStateCallback;
+
+
final class MyHandler extends Handler {
public MyHandler(Looper looper) {
super(looper, null, true);
@@ -569,6 +576,7 @@
mDailyFile = null;
mHandler = null;
mExternalSync = null;
+ mPlatformIdleStateCallback = null;
clearHistoryLocked();
}
@@ -2220,6 +2228,12 @@
+ cur.eventTag.string);
}
if (computeStepDetails) {
+ if (mPlatformIdleStateCallback != null) {
+ mCurHistoryStepDetails.statPlatformIdleState =
+ mPlatformIdleStateCallback.getPlatformLowPowerStats();
+ if (DEBUG) Slog.i(TAG, "WRITE PlatformIdleState:" +
+ mCurHistoryStepDetails.statPlatformIdleState);
+ }
computeHistoryStepDetails(mCurHistoryStepDetails, mLastHistoryStepDetails);
if (includeStepDetails != 0) {
mCurHistoryStepDetails.writeToParcel(dest);
@@ -7372,11 +7386,16 @@
}
public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) {
- this(new SystemClocks(), systemDir, handler, externalSync);
+ this(new SystemClocks(), systemDir, handler, externalSync, null);
+ }
+
+ public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync,
+ PlatformIdleStateCallback cb) {
+ this(new SystemClocks(), systemDir, handler, externalSync, cb);
}
public BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
- ExternalStatsSync externalSync) {
+ ExternalStatsSync externalSync, PlatformIdleStateCallback cb) {
init(clocks);
if (systemDir != null) {
@@ -7462,6 +7481,7 @@
initDischarge();
clearHistoryLocked();
updateDailyDeadlineLocked();
+ mPlatformIdleStateCallback = cb;
}
public BatteryStatsImpl(Parcel p) {
@@ -7477,6 +7497,7 @@
mExternalSync = null;
clearHistoryLocked();
readFromParcel(p);
+ mPlatformIdleStateCallback = null;
}
public void setPowerProfile(PowerProfile profile) {
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d36da9f..fb7a19f9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2428,41 +2428,49 @@
<!-- Phrase describing a time duration using minutes that is as short as possible, preferrably one character. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=6] -->
<plurals name="duration_minutes_shortest">
+ <item quantity="one"><xliff:g example="1" id="count">%d</xliff:g>m</item>
<item quantity="other"><xliff:g example="2" id="count">%d</xliff:g>m</item>
</plurals>
<!-- Phrase describing a time duration using hours that is as short as possible, preferrably one character. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=6] -->
<plurals name="duration_hours_shortest">
+ <item quantity="one"><xliff:g example="1" id="count">%d</xliff:g>h</item>
<item quantity="other"><xliff:g example="2" id="count">%d</xliff:g>h</item>
</plurals>
<!-- Phrase describing a time duration using days that is as short as possible, preferrably one character. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=6] -->
<plurals name="duration_days_shortest">
+ <item quantity="one"><xliff:g example="1" id="count">%d</xliff:g>d</item>
<item quantity="other"><xliff:g example="2" id="count">%d</xliff:g>d</item>
</plurals>
<!-- Phrase describing a time duration using years that is as short as possible, preferrably one character. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=6] -->
<plurals name="duration_years_shortest">
+ <item quantity="one"><xliff:g example="1" id="count">%d</xliff:g>y</item>
<item quantity="other"><xliff:g example="2" id="count">%d</xliff:g>y</item>
</plurals>
<!-- Phrase describing a time duration using minutes that is as short as possible, preferrably one character. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
<plurals name="duration_minutes_shortest_future">
+ <item quantity="one">in <xliff:g example="1" id="count">%d</xliff:g>m</item>
<item quantity="other">in <xliff:g example="2" id="count">%d</xliff:g>m</item>
</plurals>
<!-- Phrase describing a time duration using hours that is as short as possible, preferrably one character. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
<plurals name="duration_hours_shortest_future">
+ <item quantity="one">in <xliff:g example="1" id="count">%d</xliff:g>h</item>
<item quantity="other">in <xliff:g example="2" id="count">%d</xliff:g>h</item>
</plurals>
<!-- Phrase describing a time duration using days that is as short as possible, preferrably one character. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
<plurals name="duration_days_shortest_future">
+ <item quantity="one">in <xliff:g example="1" id="count">%d</xliff:g>d</item>
<item quantity="other">in <xliff:g example="2" id="count">%d</xliff:g>d</item>
</plurals>
<!-- Phrase describing a time duration using years that is as short as possible, preferrably one character. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
<plurals name="duration_years_shortest_future">
+ <item quantity="one">in <xliff:g example="1" id="count">%d</xliff:g>y</item>
<item quantity="other">in <xliff:g example="2" id="count">%d</xliff:g>y</item>
</plurals>
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 28ed84f..907616c 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -44,6 +44,7 @@
Key.TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN,
Key.QS_HOTSPOT_ADDED,
Key.QS_DATA_SAVER_ADDED,
+ Key.QS_DATA_SAVER_DIALOG_SHOWN,
Key.QS_INVERT_COLORS_ADDED,
Key.QS_WORK_ADDED,
Key.QS_NIGHT_ADDED,
@@ -63,6 +64,7 @@
String TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN = "TvPictureInPictureOnboardingShown";
String QS_HOTSPOT_ADDED = "QsHotspotAdded";
String QS_DATA_SAVER_ADDED = "QsDataSaverAdded";
+ String QS_DATA_SAVER_DIALOG_SHOWN = "QsDataSaverDialogShown";
String QS_INVERT_COLORS_ADDED = "QsInvertColorsAdded";
String QS_WORK_ADDED = "QsWorkAdded";
String QS_NIGHT_ADDED = "QsNightAdded";
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index dded595..0ce805e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -14,12 +14,15 @@
package com.android.systemui.qs.tiles;
+import android.content.DialogInterface;
import android.content.Intent;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.DataSaverController;
public class DataSaverTile extends QSTile<QSTile.BooleanState> implements
@@ -53,6 +56,29 @@
@Override
protected void handleClick() {
+ if (Prefs.getBoolean(mContext, Prefs.Key.QS_DATA_SAVER_DIALOG_SHOWN, false)) {
+ // Do it right away.
+ toggleDataSaver();
+ return;
+ }
+ // Shows dialog first
+ SystemUIDialog dialog = new SystemUIDialog(mContext);
+ dialog.setTitle(com.android.internal.R.string.data_saver_enable_title);
+ dialog.setMessage(com.android.internal.R.string.data_saver_description);
+ dialog.setPositiveButton(com.android.internal.R.string.data_saver_enable_button,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ toggleDataSaver();
+ }
+ });
+ dialog.setNegativeButton(com.android.internal.R.string.cancel, null);
+ dialog.setShowForAllUsers(true);
+ dialog.show();
+ Prefs.putBoolean(mContext, Prefs.Key.QS_DATA_SAVER_DIALOG_SHOWN, true);
+ }
+
+ private void toggleDataSaver() {
mState.value = !mDataSaverController.isDataSaverEnabled();
MetricsLogger.action(mContext, getMetricsCategory(), mState.value);
mDataSaverController.setDataSaverEnabled(mState.value);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 8239425..5b16fce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -277,6 +277,10 @@
int intrinsicBefore = getIntrinsicHeight();
mIsHeadsUp = isHeadsUp;
mPrivateLayout.setHeadsUp(isHeadsUp);
+ if (mIsSummaryWithChildren) {
+ // The overflow might change since we allow more lines as HUN.
+ mChildrenContainer.updateGroupOverflow();
+ }
if (intrinsicBefore != getIntrinsicHeight()) {
notifyHeightChanged(false /* needsAnimation */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 7be50c4..81303fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar;
import android.app.Notification;
+import android.app.PendingIntent;
import android.app.RemoteInput;
import android.content.Context;
import android.graphics.Rect;
@@ -118,6 +119,8 @@
private int mTransformationStartVisibleType;
private boolean mUserExpanding;
private int mSingleLineWidthIndention;
+ private PendingIntent mPreviousExpandedRemoteInputIntent;
+ private PendingIntent mPreviousHeadsUpRemoteInputIntent;
public NotificationContentView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -280,13 +283,19 @@
mContractedChild.animate().cancel();
removeView(mContractedChild);
}
+ mPreviousExpandedRemoteInputIntent =
+ mExpandedRemoteInput != null ? mExpandedRemoteInput.getPendingIntent() : null;
if (mExpandedChild != null) {
mExpandedChild.animate().cancel();
removeView(mExpandedChild);
+ mExpandedRemoteInput = null;
}
+ mPreviousHeadsUpRemoteInputIntent =
+ mHeadsUpRemoteInput != null ? mHeadsUpRemoteInput.getPendingIntent() : null;
if (mHeadsUpChild != null) {
mHeadsUpChild.animate().cancel();
removeView(mHeadsUpChild);
+ mHeadsUpRemoteInput = null;
}
mContractedChild = null;
mExpandedChild = null;
@@ -496,6 +505,12 @@
}
int visibleType = calculateVisibleType();
if (visibleType != mVisibleType || force) {
+ View visibleView = getViewForVisibleType(visibleType);
+ if (visibleView != null) {
+ visibleView.setVisibility(VISIBLE);
+ transferRemoteInputFocus(visibleType);
+ }
+
if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
|| (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)
|| (visibleType == VISIBLE_TYPE_SINGLELINE && mSingleLineView != null)
@@ -559,6 +574,19 @@
});
}
+ private void transferRemoteInputFocus(int visibleType) {
+ if (visibleType == VISIBLE_TYPE_HEADSUP
+ && mHeadsUpRemoteInput != null
+ && (mExpandedRemoteInput != null && mExpandedRemoteInput.isActive())) {
+ mHeadsUpRemoteInput.stealFocusFrom(mExpandedRemoteInput);
+ }
+ if (visibleType == VISIBLE_TYPE_EXPANDED
+ && mExpandedRemoteInput != null
+ && (mHeadsUpRemoteInput != null && mHeadsUpRemoteInput.isActive())) {
+ mExpandedRemoteInput.stealFocusFrom(mHeadsUpRemoteInput);
+ }
+ }
+
/**
* @param visibleType one of the static enum types in this view
* @return the corresponding transformable view according to the given visible type
@@ -736,6 +764,8 @@
updateShowingLegacyBackground();
selectLayout(false /* animate */, true /* force */);
setDark(mDark, false /* animate */, 0 /* delay */);
+ mPreviousExpandedRemoteInputIntent = null;
+ mPreviousHeadsUpRemoteInputIntent = null;
}
private void updateSingleLineView() {
@@ -771,19 +801,23 @@
View bigContentView = mExpandedChild;
if (bigContentView != null) {
- mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput);
+ mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput,
+ mPreviousExpandedRemoteInputIntent);
} else {
mExpandedRemoteInput = null;
}
+
View headsUpContentView = mHeadsUpChild;
if (headsUpContentView != null) {
- mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput);
+ mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput,
+ mPreviousHeadsUpRemoteInputIntent);
} else {
mHeadsUpRemoteInput = null;
}
}
- private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry, boolean hasRemoteInput) {
+ private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry,
+ boolean hasRemoteInput, PendingIntent existingPendingIntent) {
View actionContainerCandidate = view.findViewById(
com.android.internal.R.id.actions_container);
if (actionContainerCandidate instanceof FrameLayout) {
@@ -814,6 +848,24 @@
existing.setBackgroundColor(NotificationColorUtil.ensureTextBackgroundColor(color,
mContext.getColor(R.color.remote_input_text),
mContext.getColor(R.color.remote_input_hint)));
+
+ if (existingPendingIntent != null || existing.isActive()) {
+ // The current action could be gone, or the pending intent no longer valid.
+ // If we find a matching action in the new notification, focus, otherwise close.
+ Notification.Action[] actions = entry.notification.getNotification().actions;
+ if (existingPendingIntent != null) {
+ existing.setPendingIntent(existingPendingIntent);
+ }
+ if (existing.updatePendingIntentFromActions(actions)) {
+ if (!existing.isActive()) {
+ existing.focus();
+ }
+ } else {
+ if (existing.isActive()) {
+ existing.close();
+ }
+ }
+ }
}
return existing;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
index 3c95a78..4ce330c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
@@ -52,7 +52,7 @@
// This also clears the existing types
super.updateTransformedTypes();
if (mActions != null) {
- mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TEXT,
+ mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_ACTIONS,
mActions);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index 7a6d080..ddded49 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -25,12 +25,14 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.phone.StatusBarWindowView;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
/**
* Controls showing and hiding of the brightness mirror.
*/
public class BrightnessMirrorController {
+ private final NotificationStackScrollLayout mStackScroller;
public long TRANSITION_DURATION_OUT = 150;
public long TRANSITION_DURATION_IN = 200;
@@ -45,10 +47,13 @@
mScrimBehind = (ScrimView) statusBarWindow.findViewById(R.id.scrim_behind);
mBrightnessMirror = statusBarWindow.findViewById(R.id.brightness_mirror);
mNotificationPanel = statusBarWindow.findViewById(R.id.notification_panel);
+ mStackScroller = (NotificationStackScrollLayout) statusBarWindow.findViewById(
+ R.id.notification_stack_scroller);
}
public void showMirror() {
mBrightnessMirror.setVisibility(View.VISIBLE);
+ mStackScroller.setFadedOut(true);
mScrimBehind.animateViewAlpha(0.0f, TRANSITION_DURATION_OUT, Interpolators.ALPHA_OUT);
outAnimation(mNotificationPanel.animate())
.withLayer();
@@ -62,6 +67,7 @@
@Override
public void run() {
mBrightnessMirror.setVisibility(View.INVISIBLE);
+ mStackScroller.setFadedOut(false);
}
});
}
@@ -69,7 +75,8 @@
private ViewPropertyAnimator outAnimation(ViewPropertyAnimator a) {
return a.alpha(0.0f)
.setDuration(TRANSITION_DURATION_OUT)
- .setInterpolator(Interpolators.ALPHA_OUT);
+ .setInterpolator(Interpolators.ALPHA_OUT)
+ .withEndAction(null);
}
private ViewPropertyAnimator inAnimation(ViewPropertyAnimator a) {
return a.alpha(1.0f)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index ecd1772..f3033cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy;
+import android.app.Notification;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.content.Context;
@@ -43,6 +44,8 @@
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto;
import com.android.systemui.R;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.RemoteInputController;
@@ -126,10 +129,14 @@
mEditText.mShowImeOnInputConnection = false;
mController.remoteInputSent(mEntry);
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_SEND,
+ mEntry.notification.getPackageName());
try {
mPendingIntent.send(mContext, 0, fillInIntent);
} catch (PendingIntent.CanceledException e) {
Log.i(TAG, "Unable to send remote input result", e);
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_FAIL,
+ mEntry.notification.getPackageName());
}
}
@@ -164,6 +171,8 @@
mController.removeRemoteInput(mEntry);
mEntry.remoteInputText = mEditText.getText();
setVisibility(INVISIBLE);
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_CLOSE,
+ mEntry.notification.getPackageName());
}
@Override
@@ -197,6 +206,10 @@
}
public void focus() {
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_OPEN,
+ mEntry.notification.getPackageName());
+
+ setVisibility(VISIBLE);
mController.addRemoteInput(mEntry);
mEditText.setInnerFocusable(true);
mEditText.mShowImeOnInputConnection = true;
@@ -250,6 +263,7 @@
findScrollContainer();
if (mScrollContainer != null) {
mScrollContainer.requestDisallowLongPress();
+ mScrollContainer.requestDisallowDismiss();
}
}
return super.onInterceptTouchEvent(ev);
@@ -275,6 +289,63 @@
}
}
+ public boolean isActive() {
+ return mEditText.isFocused();
+ }
+
+ public void stealFocusFrom(RemoteInputView other) {
+ other.close();
+ setPendingIntent(other.mPendingIntent);
+ setRemoteInput(other.mRemoteInputs, other.mRemoteInput);
+ focus();
+ }
+
+ /**
+ * Tries to find an action in {@param actions} that matches the current pending intent
+ * of this view and updates its state to that of the found action
+ *
+ * @return true if a matching action was found, false otherwise
+ */
+ public boolean updatePendingIntentFromActions(Notification.Action[] actions) {
+ boolean found = false;
+ if (mPendingIntent == null || actions == null) {
+ return false;
+ }
+ Intent current = mPendingIntent.getIntent();
+ if (current == null) {
+ return false;
+ }
+
+ for (Notification.Action a : actions) {
+ RemoteInput[] inputs = a.getRemoteInputs();
+ if (a.actionIntent == null || inputs == null) {
+ continue;
+ }
+ Intent candidate = a.actionIntent.getIntent();
+ if (!current.filterEquals(candidate)) {
+ continue;
+ }
+
+ RemoteInput input = null;
+ for (RemoteInput i : inputs) {
+ if (i.getAllowFreeFormInput()) {
+ input = i;
+ }
+ }
+ if (input == null) {
+ continue;
+ }
+ setPendingIntent(a.actionIntent);
+ setRemoteInput(inputs, input);
+ return true;
+ }
+ return false;
+ }
+
+ public PendingIntent getPendingIntent() {
+ return mPendingIntent;
+ }
+
/**
* An EditText that changes appearance based on whether it's focusable and becomes
* un-focusable whenever the user navigates away from it or it becomes invisible.
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 be98d7a..a1e89b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -139,7 +139,9 @@
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
boolean isOverflow = i == overflowIndex;
- child.setSingleLineWidthIndention(isOverflow ? mOverflowNumber.getMeasuredWidth() : 0);
+ child.setSingleLineWidthIndention(isOverflow && mOverflowNumber != null
+ ? mOverflowNumber.getMeasuredWidth()
+ : 0);
child.measure(widthMeasureSpec, newHeightSpec);
height += child.getMeasuredHeight();
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 3e0f930..0a4dce8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -23,6 +23,7 @@
import android.animation.TimeAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.FloatRange;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
@@ -231,6 +232,7 @@
* animating.
*/
private boolean mOnlyScrollingInThisMotion;
+ private boolean mDisallowDismissInThisMotion;
private boolean mInterceptDelegateEnabled;
private boolean mDelegateToScrollView;
private boolean mDisallowScrollingInThisMotion;
@@ -327,6 +329,8 @@
};
private PorterDuffXfermode mSrcMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
private boolean mPulsing;
+ private boolean mDrawBackgroundAsSrc;
+ private boolean mFadedOut;
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -439,7 +443,12 @@
}
public void setDrawBackgroundAsSrc(boolean asSrc) {
- mBackgroundPaint.setXfermode(asSrc ? mSrcMode : null);
+ mDrawBackgroundAsSrc = asSrc;
+ updateSrcDrawing();
+ }
+
+ private void updateSrcDrawing() {
+ mBackgroundPaint.setXfermode(mDrawBackgroundAsSrc && !mFadedOut ? mSrcMode : null);
invalidate();
}
@@ -1023,7 +1032,8 @@
if (!mIsBeingDragged
&& !mExpandingNotification
&& !mExpandedInThisMotion
- && !mOnlyScrollingInThisMotion) {
+ && !mOnlyScrollingInThisMotion
+ && !mDisallowDismissInThisMotion) {
horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
}
return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt || super.onTouchEvent(ev);
@@ -1743,7 +1753,9 @@
}
private void applyCurrentBackgroundBounds() {
- mScrimController.setExcludedBackgroundArea(mCurrentBounds);
+ if (!mFadedOut) {
+ mScrimController.setExcludedBackgroundArea(mCurrentBounds);
+ }
invalidate();
}
@@ -2003,7 +2015,8 @@
if (!mIsBeingDragged
&& !mExpandingNotification
&& !mExpandedInThisMotion
- && !mOnlyScrollingInThisMotion) {
+ && !mOnlyScrollingInThisMotion
+ && !mDisallowDismissInThisMotion) {
swipeWantsIt = mSwipeHelper.onInterceptTouchEvent(ev);
}
return swipeWantsIt || scrollWantsIt || expandWantsIt || super.onInterceptTouchEvent(ev);
@@ -2031,6 +2044,7 @@
mExpandedInThisMotion = false;
mOnlyScrollingInThisMotion = !mScroller.isFinished();
mDisallowScrollingInThisMotion = false;
+ mDisallowDismissInThisMotion = false;
mTouchIsClick = true;
mInitialTouchX = ev.getX();
mInitialTouchY = ev.getY();
@@ -2695,6 +2709,11 @@
removeLongPressCallback();
}
+ @Override
+ public void requestDisallowDismiss() {
+ mDisallowDismissInThisMotion = true;
+ }
+
public void removeLongPressCallback() {
mSwipeHelper.removeLongPressCallback();
}
@@ -3421,6 +3440,24 @@
updateNotificationAnimationStates();
}
+ public void setFadedOut(boolean fadingOut) {
+ if (fadingOut != mFadedOut) {
+ mFadedOut = fadingOut;
+ if (fadingOut) {
+ mScrimController.setExcludedBackgroundArea(null);
+ } else {
+ applyCurrentBackgroundBounds();
+ }
+ updateSrcDrawing();
+ }
+ }
+
+ @Override
+ public void setAlpha(@FloatRange(from = 0.0, to = 1.0) float alpha) {
+ super.setAlpha(alpha);
+ setFadedOut(alpha != 1.0f);
+ }
+
/**
* A listener that is notified when some child locations might have changed.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java
index a35465e..64efa69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java
@@ -33,4 +33,9 @@
* Request that the view is made visible by scrolling to it.
*/
void scrollTo(View v);
+
+ /**
+ * Request that the view does not dismiss for the current touch.
+ */
+ void requestDisallowDismiss();
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 7b3fd66..f49235c 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2169,6 +2169,24 @@
// User blacklisted an app for Data Saver mode; action pass package name of app.
ACTION_DATA_SAVER_BLACKLIST = 396;
+ // User opened a remote input view associated with a notification. Passes package name of app
+ // that posted the notification. Note that this can also happen transiently during notification
+ // reinflation.
+ ACTION_REMOTE_INPUT_OPEN = 397;
+
+ // User attempt to send data through a remote input view associated with a notification.
+ // Passes package name of app that posted the notification. May succeed or fail.
+ ACTION_REMOTE_INPUT_SEND = 398;
+
+ // Failed attempt to send data through a remote input view associated with a
+ // notification. Passes package name of app that posted the notification.
+ ACTION_REMOTE_INPUT_FAIL = 399;
+
+ // User closed a remote input view associated with a notification. Passes package name of app
+ // that posted the notification. Note that this can also happen transiently during notification
+ // reinflation.
+ ACTION_REMOTE_INPUT_CLOSE = 400;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 1b85016..fc2e95d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -151,7 +151,10 @@
private static final int WINDOW_ID_UNKNOWN = -1;
- private static int sIdCounter = 0;
+ // Each service has an ID. Also provide one for magnification gesture handling
+ public static final int MAGNIFICATION_GESTURE_HANDLER_ID = 0;
+
+ private static int sIdCounter = MAGNIFICATION_GESTURE_HANDLER_ID + 1;
private static int sNextWindowId;
@@ -183,8 +186,6 @@
private MagnificationController mMagnificationController;
- private boolean mUnregisterMagnificationOnReset;
-
private InteractionBridge mInteractionBridge;
private AlertDialog mEnableTouchExplorationDialog;
@@ -784,11 +785,6 @@
float scale, float centerX, float centerY) {
synchronized (mLock) {
notifyMagnificationChangedLocked(region, scale, centerX, centerY);
-
- if (mUnregisterMagnificationOnReset && scale == 1.0f) {
- mUnregisterMagnificationOnReset = false;
- mMagnificationController.unregister();
- }
}
}
@@ -1736,25 +1732,17 @@
}
private void updateMagnificationLocked(UserState userState) {
- final int userId = userState.mUserId;
- if (userId == mCurrentUserId && mMagnificationController != null) {
- if (userState.mIsDisplayMagnificationEnabled ||
- userHasMagnificationServicesLocked(userState)) {
- mMagnificationController.setUserId(userState.mUserId);
- } else {
- // If the user no longer has any magnification-controlling
- // services and is not using magnification gestures, then
- // reset the state to normal.
- if (mMagnificationController.resetIfNeeded(true)) {
- // Animations are still running, so wait until we receive a
- // callback verifying that we've reset magnification.
- mUnregisterMagnificationOnReset = true;
- } else {
- mUnregisterMagnificationOnReset = false;
- mMagnificationController.unregister();
- mMagnificationController = null;
- }
- }
+ if (userState.mUserId != mCurrentUserId) {
+ return;
+ }
+
+ if (userState.mIsDisplayMagnificationEnabled ||
+ userHasMagnificationServicesLocked(userState)) {
+ // Initialize the magnification controller if necessary
+ getMagnificationController();
+ mMagnificationController.register();
+ } else if (mMagnificationController != null) {
+ mMagnificationController.unregister();
}
}
@@ -2152,7 +2140,6 @@
synchronized (mLock) {
if (mMagnificationController == null) {
mMagnificationController = new MagnificationController(mContext, this, mLock);
- mMagnificationController.register();
mMagnificationController.setUserId(mCurrentUserId);
}
return mMagnificationController;
@@ -2886,7 +2873,7 @@
final long identity = Binder.clearCallingIdentity();
try {
final Region region = Region.obtain();
- getMagnificationController().getMagnifiedRegion(region);
+ getMagnificationController().getMagnificationRegion(region);
return region;
} finally {
Binder.restoreCallingIdentity(identity);
@@ -2957,7 +2944,7 @@
final long identity = Binder.clearCallingIdentity();
try {
return getMagnificationController().setScaleAndCenter(
- scale, centerX, centerY, animate);
+ scale, centerX, centerY, animate, mId);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -3090,10 +3077,11 @@
userState.mInstalledServices.remove(mAccessibilityServiceInfo);
userState.mEnabledServices.remove(mComponentName);
userState.destroyUiAutomationService();
- if (readConfigurationForUserStateLocked(userState)) {
- onUserStateChangedLocked(userState);
- }
}
+ if (mId == getMagnificationController().getIdOfLastServiceToMagnify()) {
+ getMagnificationController().resetIfNeeded(true);
+ }
+ onUserStateChangedLocked(userState);
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index f1b3722..027b6e2 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -17,6 +17,7 @@
package com.android.server.accessibility;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.SomeArgs;
import com.android.server.LocalServices;
@@ -60,6 +61,8 @@
private static final int DEFAULT_SCREEN_MAGNIFICATION_AUTO_UPDATE = 1;
+ private static final int INVALID_ID = -1;
+
private static final float DEFAULT_MAGNIFICATION_SCALE = 2.0f;
private static final float MIN_SCALE = 1.0f;
@@ -80,9 +83,8 @@
*/
private final MagnificationSpec mCurrentMagnificationSpec = MagnificationSpec.obtain();
- private final Region mMagnifiedRegion = Region.obtain();
- private final Region mAvailableRegion = Region.obtain();
- private final Rect mMagnifiedBounds = new Rect();
+ private final Region mMagnificationRegion = Region.obtain();
+ private final Rect mMagnificationBounds = new Rect();
private final Rect mTempRect = new Rect();
private final Rect mTempRect1 = new Rect();
@@ -97,35 +99,67 @@
private int mUserId;
+ private int mIdOfLastServiceToMagnify = INVALID_ID;
+
+ // Flag indicating that we are registered with window manager.
+ private boolean mRegistered;
+
+ private boolean mUnregisterPending;
+
public MagnificationController(Context context, AccessibilityManagerService ams, Object lock) {
mAms = ams;
mContentResolver = context.getContentResolver();
mScreenStateObserver = new ScreenStateObserver(context, this);
mWindowStateObserver = new WindowStateObserver(context, this);
- mSpecAnimationBridge = new SpecAnimationBridge(context);
mLock = lock;
+ mSpecAnimationBridge = new SpecAnimationBridge(context, mLock);
}
/**
- * Registers magnification-related observers.
+ * Start tracking the magnification region for services that control magnification and the
+ * magnification gesture handler.
+ *
+ * This tracking imposes a cost on the system, so we avoid tracking this data
+ * unless it's required.
*/
public void register() {
- mScreenStateObserver.register();
- mWindowStateObserver.register();
-
- // Obtain initial state.
- mWindowStateObserver.getRegions(mMagnifiedRegion, mAvailableRegion);
- mMagnifiedRegion.getBounds(mMagnifiedBounds);
+ synchronized (mLock) {
+ if (!mRegistered) {
+ mScreenStateObserver.register();
+ mWindowStateObserver.register();
+ mSpecAnimationBridge.setEnabled(true);
+ // Obtain initial state.
+ mWindowStateObserver.getMagnificationRegion(mMagnificationRegion);
+ mMagnificationRegion.getBounds(mMagnificationBounds);
+ mRegistered = true;
+ }
+ }
}
/**
- * Unregisters magnification-related observers.
+ * Stop requiring tracking the magnification region. We may remain registered while we
+ * reset magnification.
*/
public void unregister() {
- mSpecAnimationBridge.cancel();
+ synchronized (mLock) {
+ if (!isMagnifying()) {
+ unregisterInternalLocked();
+ } else {
+ mUnregisterPending = true;
+ resetLocked(true);
+ }
+ }
+ }
- mScreenStateObserver.unregister();
- mWindowStateObserver.unregister();
+ private void unregisterInternalLocked() {
+ if (mRegistered) {
+ mSpecAnimationBridge.setEnabled(false);
+ mScreenStateObserver.unregister();
+ mWindowStateObserver.unregister();
+ mMagnificationRegion.setEmpty();
+ mRegistered = false;
+ }
+ mUnregisterPending = false;
}
/**
@@ -137,24 +171,22 @@
}
/**
- * Sets the magnified and available regions.
+ * Update our copy of the current magnification region
*
* @param magnified the magnified region
- * @param available the region available for magnification
* @param updateSpec {@code true} to update the scale and center based on
* the region bounds, {@code false} to leave them as-is
*/
- private void setMagnifiedRegion(Region magnified, Region available, boolean updateSpec) {
+ private void onMagnificationRegionChanged(Region magnified, boolean updateSpec) {
synchronized (mLock) {
boolean magnificationChanged = false;
boolean boundsChanged = false;
- if (!mMagnifiedRegion.equals(magnified)) {
- mMagnifiedRegion.set(magnified);
- mMagnifiedRegion.getBounds(mMagnifiedBounds);
+ if (!mMagnificationRegion.equals(magnified)) {
+ mMagnificationRegion.set(magnified);
+ mMagnificationRegion.getBounds(mMagnificationBounds);
boundsChanged = true;
}
- mAvailableRegion.set(available);
if (updateSpec) {
final MagnificationSpec sentSpec = mSpecAnimationBridge.mSentMagnificationSpec;
final float scale = sentSpec.scale;
@@ -162,12 +194,12 @@
final float offsetY = sentSpec.offsetY;
// Compute the new center and update spec as needed.
- final float centerX = (mMagnifiedBounds.width() / 2.0f
- + mMagnifiedBounds.left - offsetX) / scale;
- final float centerY = (mMagnifiedBounds.height() / 2.0f
- + mMagnifiedBounds.top - offsetY) / scale;
+ final float centerX = (mMagnificationBounds.width() / 2.0f
+ + mMagnificationBounds.left - offsetX) / scale;
+ final float centerY = (mMagnificationBounds.height() / 2.0f
+ + mMagnificationBounds.top - offsetY) / scale;
magnificationChanged = setScaleAndCenterLocked(
- scale, centerX, centerY, false);
+ scale, centerX, centerY, false, INVALID_ID);
}
// If magnification changed we already notified for the change.
@@ -178,7 +210,7 @@
}
/**
- * Returns whether the magnified region contains the specified
+ * Returns whether the magnification region contains the specified
* screen-relative coordinates.
*
* @param x the screen-relative X coordinate to check
@@ -186,51 +218,36 @@
* @return {@code true} if the coordinate is contained within the
* magnified region, or {@code false} otherwise
*/
- public boolean magnifiedRegionContains(float x, float y) {
+ public boolean magnificationRegionContains(float x, float y) {
synchronized (mLock) {
- return mMagnifiedRegion.contains((int) x, (int) y);
- }
- }
-
- /**
- * Returns whether the region available for magnification contains the
- * specified screen-relative coordinates.
- *
- * @param x the screen-relative X coordinate to check
- * @param y the screen-relative Y coordinate to check
- * @return {@code true} if the coordinate is contained within the
- * region available for magnification, or {@code false} otherwise
- */
- private boolean availableRegionContains(float x, float y) {
- synchronized (mLock) {
- return mAvailableRegion.contains((int) x, (int) y);
+ return mMagnificationRegion.contains((int) x, (int) y);
}
}
/**
* Populates the specified rect with the screen-relative bounds of the
- * magnified region. If magnification is not enabled, the returned
+ * magnification region. If magnification is not enabled, the returned
* bounds will be empty.
*
* @param outBounds rect to populate with the bounds of the magnified
* region
*/
- public void getMagnifiedBounds(@NonNull Rect outBounds) {
+ public void getMagnificationBounds(@NonNull Rect outBounds) {
synchronized (mLock) {
- outBounds.set(mMagnifiedBounds);
+ outBounds.set(mMagnificationBounds);
}
}
/**
- * Populates the specified region with the screen-relative magnified
+ * Populates the specified region with the screen-relative magnification
* region. If magnification is not enabled, then the returned region
* will be empty.
*
* @param outRegion the region to populate
*/
- public void getMagnifiedRegion(@NonNull Region outRegion) {
+ public void getMagnificationRegion(@NonNull Region outRegion) {
synchronized (mLock) {
- outRegion.set(mMagnifiedRegion);
+ outRegion.set(mMagnificationRegion);
}
}
@@ -263,8 +280,8 @@
*/
public float getCenterX() {
synchronized (mLock) {
- return (mMagnifiedBounds.width() / 2.0f
- + mMagnifiedBounds.left - getOffsetX()) / getScale();
+ return (mMagnificationBounds.width() / 2.0f
+ + mMagnificationBounds.left - getOffsetX()) / getScale();
}
}
@@ -286,8 +303,8 @@
*/
public float getCenterY() {
synchronized (mLock) {
- return (mMagnifiedBounds.height() / 2.0f
- + mMagnifiedBounds.top - getOffsetY()) / getScale();
+ return (mMagnificationBounds.height() / 2.0f
+ + mMagnificationBounds.top - getOffsetY()) / getScale();
}
}
@@ -335,17 +352,25 @@
*/
public boolean reset(boolean animate) {
synchronized (mLock) {
- final MagnificationSpec spec = mCurrentMagnificationSpec;
- final boolean changed = !spec.isNop();
- if (changed) {
- spec.clear();
- onMagnificationChangedLocked();
- }
- mSpecAnimationBridge.updateSentSpec(spec, animate);
- return changed;
+ return resetLocked(animate);
}
}
+ private boolean resetLocked(boolean animate) {
+ if (!mRegistered) {
+ return false;
+ }
+ final MagnificationSpec spec = mCurrentMagnificationSpec;
+ final boolean changed = !spec.isNop();
+ if (changed) {
+ spec.clear();
+ onMagnificationChangedLocked();
+ }
+ mIdOfLastServiceToMagnify = INVALID_ID;
+ mSpecAnimationBridge.updateSentSpec(spec, animate);
+ return changed;
+ }
+
/**
* Scales the magnified region around the specified pivot point,
* optionally animating the transition. If animation is disabled, the
@@ -356,16 +381,20 @@
* @param pivotY the screen-relative Y coordinate around which to scale
* @param animate {@code true} to animate the transition, {@code false}
* to transition immediately
+ * @param id the ID of the service requesting the change
* @return {@code true} if the magnification spec changed, {@code false} if
* the spec did not change
*/
- public boolean setScale(float scale, float pivotX, float pivotY, boolean animate) {
+ public boolean setScale(float scale, float pivotX, float pivotY, boolean animate, int id) {
synchronized (mLock) {
+ if (!mRegistered) {
+ return false;
+ }
// Constrain scale immediately for use in the pivot calculations.
scale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
final Rect viewport = mTempRect;
- mMagnifiedRegion.getBounds(viewport);
+ mMagnificationRegion.getBounds(viewport);
final MagnificationSpec spec = mCurrentMagnificationSpec;
final float oldScale = spec.scale;
final float oldCenterX = (viewport.width() / 2.0f - spec.offsetX) / oldScale;
@@ -376,7 +405,8 @@
final float offsetY = (oldCenterY - normPivotY) * (oldScale / scale);
final float centerX = normPivotX + offsetX;
final float centerY = normPivotY + offsetY;
- return setScaleAndCenterLocked(scale, centerX, centerY, animate);
+ mIdOfLastServiceToMagnify = id;
+ return setScaleAndCenterLocked(scale, centerX, centerY, animate, id);
}
}
@@ -390,12 +420,16 @@
* center
* @param animate {@code true} to animate the transition, {@code false}
* to transition immediately
+ * @param id the ID of the service requesting the change
* @return {@code true} if the magnification spec changed, {@code false} if
* the spec did not change
*/
- public boolean setCenter(float centerX, float centerY, boolean animate) {
+ public boolean setCenter(float centerX, float centerY, boolean animate, int id) {
synchronized (mLock) {
- return setScaleAndCenterLocked(Float.NaN, centerX, centerY, animate);
+ if (!mRegistered) {
+ return false;
+ }
+ return setScaleAndCenterLocked(Float.NaN, centerX, centerY, animate, id);
}
}
@@ -411,19 +445,27 @@
* center and scale, or {@link Float#NaN} to leave unchanged
* @param animate {@code true} to animate the transition, {@code false}
* to transition immediately
+ * @param id the ID of the service requesting the change
* @return {@code true} if the magnification spec changed, {@code false} if
* the spec did not change
*/
- public boolean setScaleAndCenter(float scale, float centerX, float centerY, boolean animate) {
+ public boolean setScaleAndCenter(
+ float scale, float centerX, float centerY, boolean animate, int id) {
synchronized (mLock) {
- return setScaleAndCenterLocked(scale, centerX, centerY, animate);
+ if (!mRegistered) {
+ return false;
+ }
+ return setScaleAndCenterLocked(scale, centerX, centerY, animate, id);
}
}
private boolean setScaleAndCenterLocked(float scale, float centerX, float centerY,
- boolean animate) {
+ boolean animate, int id) {
final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY);
mSpecAnimationBridge.updateSentSpec(mCurrentMagnificationSpec, animate);
+ if (isMagnifying() && (id != INVALID_ID)) {
+ mIdOfLastServiceToMagnify = id;
+ }
return changed;
}
@@ -432,22 +474,42 @@
*
* @param offsetX the amount in pixels to offset the X center
* @param offsetY the amount in pixels to offset the Y center
+ * @param id the ID of the service requesting the change
*/
- public void offsetMagnifiedRegionCenter(float offsetX, float offsetY) {
+ public void offsetMagnifiedRegionCenter(float offsetX, float offsetY, int id) {
synchronized (mLock) {
+ if (!mRegistered) {
+ return;
+ }
+
final MagnificationSpec currSpec = mCurrentMagnificationSpec;
final float nonNormOffsetX = currSpec.offsetX - offsetX;
currSpec.offsetX = MathUtils.constrain(nonNormOffsetX, getMinOffsetXLocked(), 0);
final float nonNormOffsetY = currSpec.offsetY - offsetY;
currSpec.offsetY = MathUtils.constrain(nonNormOffsetY, getMinOffsetYLocked(), 0);
+ if (id != INVALID_ID) {
+ mIdOfLastServiceToMagnify = id;
+ }
mSpecAnimationBridge.updateSentSpec(currSpec, false);
}
}
+ /**
+ * Get the ID of the last service that changed the magnification spec.
+ *
+ * @return The id
+ */
+ public int getIdOfLastServiceToMagnify() {
+ return mIdOfLastServiceToMagnify;
+ }
+
private void onMagnificationChangedLocked() {
mAms.onMagnificationStateChanged();
- mAms.notifyMagnificationChanged(mMagnifiedRegion,
+ mAms.notifyMagnificationChanged(mMagnificationRegion,
getScale(), getCenterX(), getCenterY());
+ if (mUnregisterPending && !isMagnifying()) {
+ unregisterInternalLocked();
+ }
}
/**
@@ -503,8 +565,8 @@
scale = getScale();
}
- // Ensure requested center is within the available region.
- if (!availableRegionContains(centerX, centerY)) {
+ // Ensure requested center is within the magnification region.
+ if (!magnificationRegionContains(centerX, centerY)) {
return false;
}
@@ -518,16 +580,16 @@
changed = true;
}
- final float nonNormOffsetX = mMagnifiedBounds.width() / 2.0f
- + mMagnifiedBounds.left - centerX * scale;
+ final float nonNormOffsetX = mMagnificationBounds.width() / 2.0f
+ + mMagnificationBounds.left - centerX * scale;
final float offsetX = MathUtils.constrain(nonNormOffsetX, getMinOffsetXLocked(), 0);
if (Float.compare(currSpec.offsetX, offsetX) != 0) {
currSpec.offsetX = offsetX;
changed = true;
}
- final float nonNormOffsetY = mMagnifiedBounds.height() / 2.0f
- + mMagnifiedBounds.top - centerY * scale;
+ final float nonNormOffsetY = mMagnificationBounds.height() / 2.0f
+ + mMagnificationBounds.top - centerY * scale;
final float offsetY = MathUtils.constrain(nonNormOffsetY, getMinOffsetYLocked(), 0);
if (Float.compare(currSpec.offsetY, offsetY) != 0) {
currSpec.offsetY = offsetY;
@@ -542,12 +604,12 @@
}
private float getMinOffsetXLocked() {
- final float viewportWidth = mMagnifiedBounds.width();
+ final float viewportWidth = mMagnificationBounds.width();
return viewportWidth - viewportWidth * mCurrentMagnificationSpec.scale;
}
private float getMinOffsetYLocked() {
- final float viewportHeight = mMagnifiedBounds.height();
+ final float viewportHeight = mMagnificationBounds.height();
return viewportHeight - viewportHeight * mCurrentMagnificationSpec.scale;
}
@@ -595,7 +657,7 @@
final float scale = getSentScale();
final float offsetX = getSentOffsetX();
final float offsetY = getSentOffsetY();
- getMagnifiedBounds(outFrame);
+ getMagnificationBounds(outFrame);
outFrame.offset((int) -offsetX, (int) -offsetY);
outFrame.scale(1.0f / scale);
}
@@ -603,7 +665,7 @@
private void requestRectangleOnScreen(int left, int top, int right, int bottom) {
synchronized (mLock) {
final Rect magnifiedFrame = mTempRect;
- getMagnifiedBounds(magnifiedFrame);
+ getMagnificationBounds(magnifiedFrame);
if (!magnifiedFrame.intersects(left, top, right, bottom)) {
return;
}
@@ -640,7 +702,7 @@
}
final float scale = getScale();
- offsetMagnifiedRegionCenter(scrollX * scale, scrollY * scale);
+ offsetMagnifiedRegionCenter(scrollX * scale, scrollY * scale, INVALID_ID);
}
}
@@ -656,7 +718,7 @@
/**
* The magnification spec that was sent to the window manager. This should
- * only be accessed and modified on the main (e.g. animation) thread.
+ * only be accessed with the lock held.
*/
private final MagnificationSpec mSentMagnificationSpec = MagnificationSpec.obtain();
@@ -667,8 +729,13 @@
private final ValueAnimator mTransformationAnimator;
private final long mMainThreadId;
+ private final Object mLock;
- private SpecAnimationBridge(Context context) {
+ @GuardedBy("mLock")
+ private boolean mEnabled = false;
+
+ private SpecAnimationBridge(Context context, Object lock) {
+ mLock = lock;
final Looper mainLooper = context.getMainLooper();
mMainThreadId = mainLooper.getThread().getId();
@@ -685,9 +752,19 @@
mTransformationAnimator.setInterpolator(new DecelerateInterpolator(2.5f));
}
- public void cancel() {
- if (mTransformationAnimator != null && mTransformationAnimator.isRunning()) {
- mTransformationAnimator.cancel();
+ /**
+ * Enabled means the bridge will accept input. When not enabled, the output of the animator
+ * will be ignored
+ */
+ public void setEnabled(boolean enabled) {
+ synchronized (mLock) {
+ if (enabled != mEnabled) {
+ mEnabled = enabled;
+ if (!mEnabled) {
+ mSentMagnificationSpec.clear();
+ mWindowManager.setMagnificationSpec(mSentMagnificationSpec);
+ }
+ }
}
}
@@ -710,28 +787,32 @@
}
// If the current and sent specs don't match, update the sent spec.
- final boolean changed = !mSentMagnificationSpec.equals(spec);
- if (changed) {
- if (animate) {
- animateMagnificationSpec(spec);
- } else {
- setMagnificationSpec(spec);
+ synchronized (mLock) {
+ final boolean changed = !mSentMagnificationSpec.equals(spec);
+ if (changed) {
+ if (animate) {
+ animateMagnificationSpecLocked(spec);
+ } else {
+ setMagnificationSpecLocked(spec);
+ }
}
}
}
- private void animateMagnificationSpec(MagnificationSpec toSpec) {
+ private void animateMagnificationSpecLocked(MagnificationSpec toSpec) {
mTransformationAnimator.setObjectValues(mSentMagnificationSpec, toSpec);
mTransformationAnimator.start();
}
- private void setMagnificationSpec(MagnificationSpec spec) {
- if (DEBUG_SET_MAGNIFICATION_SPEC) {
- Slog.i(LOG_TAG, "Sending: " + spec);
- }
+ private void setMagnificationSpecLocked(MagnificationSpec spec) {
+ if (mEnabled) {
+ if (DEBUG_SET_MAGNIFICATION_SPEC) {
+ Slog.i(LOG_TAG, "Sending: " + spec);
+ }
- mSentMagnificationSpec.setTo(spec);
- mWindowManager.setMagnificationSpec(spec);
+ mSentMagnificationSpec.setTo(spec);
+ mWindowManager.setMagnificationSpec(spec);
+ }
}
private class UpdateHandler extends Handler {
@@ -759,12 +840,16 @@
@Override
public MagnificationSpec get(SpecAnimationBridge object) {
- return object.mSentMagnificationSpec;
+ synchronized (object.mLock) {
+ return object.mSentMagnificationSpec;
+ }
}
@Override
public void set(SpecAnimationBridge object, MagnificationSpec value) {
- object.setMagnificationSpec(value);
+ synchronized (object.mLock) {
+ object.setMagnificationSpecLocked(value);
+ }
}
}
@@ -862,15 +947,14 @@
}
@Override
- public void onMagnifiedBoundsChanged(Region magnified, Region available) {
+ public void onMagnificationRegionChanged(Region magnificationRegion) {
final SomeArgs args = SomeArgs.obtain();
- args.arg1 = Region.obtain(magnified);
- args.arg2 = Region.obtain(available);
+ args.arg1 = Region.obtain(magnificationRegion);
mHandler.obtainMessage(MESSAGE_ON_MAGNIFIED_BOUNDS_CHANGED, args).sendToTarget();
}
- private void handleOnMagnifiedBoundsChanged(Region magnified, Region available) {
- mController.setMagnifiedRegion(magnified, available, mSpecIsDirty);
+ private void handleOnMagnifiedBoundsChanged(Region magnificationRegion) {
+ mController.onMagnificationRegionChanged(magnificationRegion, mSpecIsDirty);
mSpecIsDirty = false;
}
@@ -911,8 +995,15 @@
mController.resetIfNeeded(true);
}
- public void getRegions(@NonNull Region outMagnified, @NonNull Region outAvailable) {
- mWindowManager.getMagnificationRegions(outMagnified, outAvailable);
+ /**
+ * This method is used to get the magnification region in the tiny time slice between
+ * registering the callbacks and handling the message.
+ * TODO: Elimiante this extra path, perhaps by processing the message immediately
+ *
+ * @param outMagnificationRegion
+ */
+ public void getMagnificationRegion(@NonNull Region outMagnificationRegion) {
+ mWindowManager.getMagnificationRegion(outMagnificationRegion);
}
private class CallbackHandler extends Handler {
@@ -926,10 +1017,8 @@
case MESSAGE_ON_MAGNIFIED_BOUNDS_CHANGED: {
final SomeArgs args = (SomeArgs) message.obj;
final Region magnifiedBounds = (Region) args.arg1;
- final Region availableBounds = (Region) args.arg2;
- handleOnMagnifiedBoundsChanged(magnifiedBounds, availableBounds);
+ handleOnMagnifiedBoundsChanged(magnifiedBounds);
magnifiedBounds.recycle();
- availableBounds.recycle();
} break;
case MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED: {
final SomeArgs args = (SomeArgs) message.obj;
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 818ac81..39bc809 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -237,7 +237,7 @@
final float eventX = event.getX();
final float eventY = event.getY();
if (mMagnificationController.isMagnifying()
- && mMagnificationController.magnifiedRegionContains(eventX, eventY)) {
+ && mMagnificationController.magnificationRegionContains(eventX, eventY)) {
final float scale = mMagnificationController.getScale();
final float scaledOffsetX = mMagnificationController.getOffsetX();
final float scaledOffsetY = mMagnificationController.getOffsetY();
@@ -381,7 +381,8 @@
Slog.i(LOG_TAG, "Panned content by scrollX: " + distanceX
+ " scrollY: " + distanceY);
}
- mMagnificationController.offsetMagnifiedRegionCenter(distanceX, distanceY);
+ mMagnificationController.offsetMagnifiedRegionCenter(distanceX, distanceY,
+ AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
return true;
}
@@ -421,7 +422,8 @@
final float pivotX = detector.getFocusX();
final float pivotY = detector.getFocusY();
- mMagnificationController.setScale(scale, pivotX, pivotY, false);
+ mMagnificationController.setScale(scale, pivotX, pivotY, false,
+ AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
return true;
}
@@ -469,14 +471,14 @@
}
final float eventX = event.getX();
final float eventY = event.getY();
- if (mMagnificationController.magnifiedRegionContains(eventX, eventY)) {
+ if (mMagnificationController.magnificationRegionContains(eventX, eventY)) {
if (mLastMoveOutsideMagnifiedRegion) {
mLastMoveOutsideMagnifiedRegion = false;
- mMagnificationController.setCenter(eventX,
- eventY, true);
+ mMagnificationController.setCenter(eventX, eventY, true,
+ AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
} else {
- mMagnificationController.setCenter(eventX,
- eventY, false);
+ mMagnificationController.setCenter(eventX, eventY, false,
+ AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
}
} else {
mLastMoveOutsideMagnifiedRegion = true;
@@ -571,7 +573,7 @@
switch (action) {
case MotionEvent.ACTION_DOWN: {
mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
- if (!mMagnificationController.magnifiedRegionContains(
+ if (!mMagnificationController.magnificationRegionContains(
event.getX(), event.getY())) {
transitionToDelegatingStateAndClear();
return;
@@ -616,7 +618,7 @@
return;
}
mHandler.removeMessages(MESSAGE_ON_ACTION_TAP_AND_HOLD);
- if (!mMagnificationController.magnifiedRegionContains(
+ if (!mMagnificationController.magnificationRegionContains(
event.getX(), event.getY())) {
transitionToDelegatingStateAndClear();
return;
@@ -726,7 +728,8 @@
if (!mMagnificationController.isMagnifying()) {
final float targetScale = mMagnificationController.getPersistedScale();
final float scale = MathUtils.constrain(targetScale, MIN_SCALE, MAX_SCALE);
- mMagnificationController.setScaleAndCenter(scale, up.getX(), up.getY(), true);
+ mMagnificationController.setScaleAndCenter(scale, up.getX(), up.getY(), true,
+ AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
} else {
mMagnificationController.reset(true);
}
@@ -742,7 +745,8 @@
final float targetScale = mMagnificationController.getPersistedScale();
final float scale = MathUtils.constrain(targetScale, MIN_SCALE, MAX_SCALE);
- mMagnificationController.setScaleAndCenter(scale, down.getX(), down.getY(), true);
+ mMagnificationController.setScaleAndCenter(scale, down.getX(), down.getY(), true,
+ AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
transitionToState(STATE_VIEWPORT_DRAGGING);
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index f06583b..0287332 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -31,7 +31,6 @@
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
-
import android.annotation.Nullable;
import android.app.BroadcastOptions;
import android.app.Notification;
@@ -1382,6 +1381,10 @@
if (LOGD_RULES) {
log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")");
}
+ if (restrictBackground) {
+ log("onRestrictBackgroundChanged(true): disabling tethering");
+ mTethering.untetherAll();
+ }
}
@Override
@@ -1813,6 +1816,14 @@
pw.decreaseIndent();
pw.println();
+ pw.println("Metered Interfaces:");
+ pw.increaseIndent();
+ for (String value : mMeteredIfaces) {
+ pw.println(value);
+ }
+ pw.decreaseIndent();
+ pw.println();
+
pw.println("Network Requests:");
pw.increaseIndent();
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
@@ -2568,7 +2579,14 @@
public int tether(String iface) {
ConnectivityManager.enforceTetherChangePermission(mContext);
if (isTetheringSupported()) {
- return mTethering.tether(iface);
+ final int status = mTethering.tether(iface);
+ if (status == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ try {
+ mPolicyManager.onTetheringChanged(iface, true);
+ } catch (RemoteException e) {
+ }
+ }
+ return status;
} else {
return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
}
@@ -2579,7 +2597,14 @@
ConnectivityManager.enforceTetherChangePermission(mContext);
if (isTetheringSupported()) {
- return mTethering.untether(iface);
+ final int status = mTethering.untether(iface);
+ if (status == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ try {
+ mPolicyManager.onTetheringChanged(iface, false);
+ } catch (RemoteException e) {
+ }
+ }
+ return status;
} else {
return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 2516f5d..c6786de 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -79,7 +79,8 @@
* battery life.
*/
public final class BatteryStatsService extends IBatteryStats.Stub
- implements PowerManagerInternal.LowPowerModeListener {
+ implements PowerManagerInternal.LowPowerModeListener,
+ BatteryStatsImpl.PlatformIdleStateCallback {
static final String TAG = "BatteryStatsService";
/**
@@ -173,6 +174,33 @@
}
}
+ private native int getPlatformLowPowerStats(ByteBuffer outBuffer);
+ private CharsetDecoder mDecoderStat = StandardCharsets.UTF_8
+ .newDecoder()
+ .onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE)
+ .replaceWith("?");
+ private ByteBuffer mUtf8BufferStat = ByteBuffer.allocateDirect(MAX_LOW_POWER_STATS_SIZE);
+ private CharBuffer mUtf16BufferStat = CharBuffer.allocate(MAX_LOW_POWER_STATS_SIZE);
+ private static final int MAX_LOW_POWER_STATS_SIZE = 512;
+
+ @Override
+ public String getPlatformLowPowerStats() {
+ mUtf8BufferStat.clear();
+ mUtf16BufferStat.clear();
+ mDecoderStat.reset();
+ int bytesWritten = getPlatformLowPowerStats(mUtf8BufferStat);
+ if (bytesWritten < 0) {
+ return null;
+ } else if (bytesWritten == 0) {
+ return "Empty";
+ }
+ mUtf8BufferStat.limit(bytesWritten);
+ mDecoderStat.decode(mUtf8BufferStat, mUtf16BufferStat, true);
+ mUtf16BufferStat.flip();
+ return mUtf16BufferStat.toString();
+ }
+
BatteryStatsService(File systemDir, Handler handler) {
// Our handler here will be accessing the disk, use a different thread than
// what the ActivityManagerService gave us (no I/O on that one!).
@@ -182,9 +210,9 @@
mHandler = new BatteryStatsHandler(thread.getLooper());
// BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through.
- mStats = new BatteryStatsImpl(systemDir, handler, mHandler);
+ mStats = new BatteryStatsImpl(systemDir, handler, mHandler, this);
}
-
+
public void publish(Context context) {
mContext = context;
mStats.setRadioScanningTimeout(mContext.getResources().getInteger(
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 75d49c3..cdb68d8 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -220,6 +220,7 @@
private void finishUserBoot(UserState uss, IIntentReceiver resultTo) {
final int userId = uss.mHandle.getIdentifier();
+ Slog.d(TAG, "Finishing user boot " + userId);
synchronized (mService) {
// Bail if we ended up with a stale user
if (mStartedUsers.get(userId) != uss) return;
@@ -248,7 +249,8 @@
+ "): attempting unlock because parent is unlocked");
maybeUnlockUser(userId);
} else {
- Slog.d(TAG, "User " + userId + " (parent " + parent.id
+ String parentId = (parent == null) ? "<null>" : String.valueOf(parent.id);
+ Slog.d(TAG, "User " + userId + " (parent " + parentId
+ "): delaying unlock because parent is locked");
}
} else {
@@ -333,6 +335,10 @@
synchronized (mService) {
// Bail if we ended up with a stale user
if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;
+ final UserInfo userInfo = getUserInfo(userId);
+ if (userInfo == null) {
+ return;
+ }
// Only keep marching forward if user is actually unlocked
if (!isUserKeyUnlocked(userId)) return;
@@ -341,6 +347,25 @@
// Remember that we logged in
mUserManager.onUserLoggedIn(userId);
+ if (!userInfo.isInitialized()) {
+ if (userId != UserHandle.USER_SYSTEM) {
+ Slog.d(TAG, "Initializing user #" + userId);
+ Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mService.broadcastIntentLocked(null, null, intent, null,
+ new IIntentReceiver.Stub() {
+ @Override
+ public void performReceive(Intent intent, int resultCode,
+ String data, Bundle extras, boolean ordered,
+ boolean sticky, int sendingUser) {
+ // Note: performReceive is called with mService lock held
+ getUserManager().makeInitialized(userInfo.id);
+ }
+ }, 0, null, null, null, AppOpsManager.OP_NONE,
+ null, true, false, MY_PID, SYSTEM_UID, userId);
+ }
+ }
+ Slog.d(TAG, "Sending BOOT_COMPLETE user #" + userId);
final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
@@ -669,6 +694,35 @@
}
}
+ /**
+ * Start user, if its not already running.
+ * <p>The user will be brought to the foreground, if {@code foreground} parameter is set.
+ * When starting the user, multiple intents will be broadcast in the following order:</p>
+ * <ul>
+ * <li>{@link Intent#ACTION_USER_STARTED} - sent to registered receivers of the new user
+ * <li>{@link Intent#ACTION_USER_BACKGROUND} - sent to registered receivers of the outgoing
+ * user and all profiles of this user. Sent only if {@code foreground} parameter is true
+ * <li>{@link Intent#ACTION_USER_FOREGROUND} - sent to registered receivers of the new
+ * user and all profiles of this user. Sent only if {@code foreground} parameter is true
+ * <li>{@link Intent#ACTION_USER_SWITCHED} - sent to registered receivers of the new user.
+ * Sent only if {@code foreground} parameter is true
+ * <li>{@link Intent#ACTION_USER_STARTING} - ordered broadcast sent to registered receivers
+ * of the new fg user
+ * <li>{@link Intent#ACTION_LOCKED_BOOT_COMPLETED} - ordered broadcast sent to receivers of
+ * the new user
+ * <li>{@link Intent#ACTION_USER_UNLOCKED} - sent to registered receivers of the new user
+ * <li>{@link Intent#ACTION_PRE_BOOT_COMPLETED} - ordered broadcast sent to receivers of the
+ * new user. Sent only when the user is booting after a system update.
+ * <li>{@link Intent#ACTION_USER_INITIALIZE} - ordered broadcast sent to receivers of the
+ * new user. Sent only the first time a user is starting.
+ * <li>{@link Intent#ACTION_BOOT_COMPLETED} - ordered broadcast sent to receivers of the new
+ * user. Indicates that the user has finished booting.
+ * </ul>
+ *
+ * @param userId ID of the user to start
+ * @param foreground true if user should be brought to the foreground
+ * @return true if the user has been successfully started
+ */
boolean startUser(final int userId, final boolean foreground) {
if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED) {
@@ -680,7 +734,7 @@
throw new SecurityException(msg);
}
- if (DEBUG_MU) Slog.i(TAG, "starting userid:" + userId + " fore:" + foreground);
+ Slog.i(TAG, "Starting userid:" + userId + " fg:" + foreground);
final long ident = Binder.clearCallingIdentity();
try {
@@ -790,36 +844,8 @@
null, false, false, MY_PID, SYSTEM_UID, userId);
}
- if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
- if (userId != UserHandle.USER_SYSTEM) {
- Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- mService.broadcastIntentLocked(null, null, intent, null,
- new IIntentReceiver.Stub() {
- @Override
- public void performReceive(Intent intent, int resultCode,
- String data, Bundle extras, boolean ordered,
- boolean sticky, int sendingUser) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- onUserInitialized(uss, foreground,
- oldUserId, userId);
- }
- });
- }
- }, 0, null, null, null, AppOpsManager.OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, userId);
- uss.initializing = true;
- } else {
- getUserManager().makeInitialized(userInfo.id);
- }
- }
-
if (foreground) {
- if (!uss.initializing) {
- moveUserToForegroundLocked(uss, oldUserId, userId);
- }
+ moveUserToForegroundLocked(uss, oldUserId, userId);
} else {
mService.mUserController.finishUserBoot(uss);
}
@@ -996,8 +1022,8 @@
}
}
- void dispatchUserSwitch(final UserState uss, final int oldUserId,
- final int newUserId) {
+ void dispatchUserSwitch(final UserState uss, final int oldUserId, final int newUserId) {
+ Slog.d(TAG, "Dispatch onUserSwitching oldUser #" + oldUserId + " newUser #" + newUserId);
final int observerCount = mUserSwitchObservers.beginBroadcast();
if (observerCount > 0) {
final IRemoteCallback callback = new IRemoteCallback.Stub() {
@@ -1041,39 +1067,14 @@
}
void continueUserSwitch(UserState uss, int oldUserId, int newUserId) {
- completeSwitchAndInitialize(uss, oldUserId, newUserId, false, true);
- }
-
- void onUserInitialized(UserState uss, boolean foreground, int oldUserId, int newUserId) {
+ Slog.d(TAG, "Continue user switch oldUser #" + oldUserId + ", newUser #" + newUserId);
synchronized (mService) {
- if (foreground) {
- moveUserToForegroundLocked(uss, oldUserId, newUserId);
- }
+ mService.mWindowManager.stopFreezingScreen();
}
- completeSwitchAndInitialize(uss, oldUserId, newUserId, true, false);
- }
-
- void completeSwitchAndInitialize(UserState uss, int oldUserId, int newUserId,
- boolean clearInitializing, boolean clearSwitching) {
- boolean unfrozen = false;
- synchronized (mService) {
- if (clearInitializing) {
- uss.initializing = false;
- getUserManager().makeInitialized(uss.mHandle.getIdentifier());
- }
- if (clearSwitching) {
- uss.switching = false;
- }
- if (!uss.switching && !uss.initializing) {
- mService.mWindowManager.stopFreezingScreen();
- unfrozen = true;
- }
- }
- if (unfrozen) {
- mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
- mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG,
- newUserId, 0));
- }
+ uss.switching = false;
+ mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
+ mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG,
+ newUserId, 0));
stopGuestOrEphemeralUserIfBackground();
stopBackgroundUsersIfEnforced(oldUserId);
}
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index 56abd95..952283e 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -54,7 +54,6 @@
public int state = STATE_BOOTING;
public int lastState = STATE_BOOTING;
public boolean switching;
- public boolean initializing;
/**
* The last time that a provider was reported to usage stats as being brought to important
@@ -103,7 +102,6 @@
pw.print(prefix);
pw.print("state="); pw.print(stateToString(state));
if (switching) pw.print(" SWITCHING");
- if (initializing) pw.print(" INITIALIZING");
pw.println();
}
}
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
index ac5c4ae..5096b35 100644
--- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
+++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
@@ -192,11 +192,13 @@
}
}
- if (!mPendingIntents.isEmpty()) {
- pw.println();
- pw.println("Pending intents:");
- for (PendingIntent pi : mPendingIntents) {
- pw.println(pi.toString());
+ synchronized (mPendingIntents) {
+ if (!mPendingIntents.isEmpty()) {
+ pw.println();
+ pw.println("Pending intents:");
+ for (PendingIntent pi : mPendingIntents) {
+ pw.println(pi.toString());
+ }
}
}
@@ -327,9 +329,9 @@
result[i++] = e;
}
}
- }
- reference.setValue(mLastEventReference);
+ reference.setValue(mLastEventReference);
+ }
return result;
}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index c2022d5..1012f9a 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -610,6 +610,13 @@
return ConnectivityManager.TETHER_ERROR_NO_ERROR;
}
+ public void untetherAll() {
+ if (DBG) Log.d(TAG, "Untethering " + mIfaces);
+ for (String iface : mIfaces.keySet()) {
+ untether(iface);
+ }
+ }
+
public int getLastTetherError(String iface) {
TetherInterfaceSM sm = null;
synchronized (mPublicSync) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 43f47fa..0b1ece5 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1899,6 +1899,18 @@
}
@Override
+ public void onTetheringChanged(String iface, boolean tethering) {
+ // No need to enforce permission because setRestrictBackground() will do it.
+ if (LOGD) Log.d(TAG, "onTetherStateChanged(" + iface + ", " + tethering + ")");
+ synchronized (mRulesLock) {
+ if (mRestrictBackground && tethering) {
+ Log.d(TAG, "Tethering on (" + iface +"); disable Data Saver");
+ setRestrictBackground(false);
+ }
+ }
+ }
+
+ @Override
public void setRestrictBackground(boolean restrictBackground) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 3ef077b..101f56f 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -124,9 +124,9 @@
}
}
- public void getMagnificationRegionsLocked(Region outMagnified, Region outAvailable) {
+ public void getMagnificationRegionLocked(Region outMagnificationRegion) {
if (mDisplayMagnifier != null) {
- mDisplayMagnifier.getMagnificationRegionsLocked(outMagnified, outAvailable);
+ mDisplayMagnifier.getMagnificationRegionLocked(outMagnificationRegion);
}
}
@@ -400,8 +400,8 @@
return spec;
}
- public void getMagnificationRegionsLocked(Region outMagnified, Region outAvailable) {
- mMagnifedViewport.getBoundsLocked(outMagnified, outAvailable);
+ public void getMagnificationRegionLocked(Region outMagnificationRegion) {
+ mMagnifedViewport.getMagnificationRegionLocked(outMagnificationRegion);
}
public void destroyLocked() {
@@ -424,10 +424,8 @@
private final Matrix mTempMatrix = new Matrix();
- private final Region mMagnifiedBounds = new Region();
- private final Region mAvailableBounds = new Region();
- private final Region mOldMagnifiedBounds = new Region();
- private final Region mOldAvailableBounds = new Region();
+ private final Region mMagnificationRegion = new Region();
+ private final Region mOldMagnificationRegion = new Region();
private final Path mCircularPath;
@@ -463,10 +461,8 @@
recomputeBoundsLocked();
}
- public void getBoundsLocked(@NonNull Region outMagnified,
- @NonNull Region outAvailable) {
- outMagnified.set(mMagnifiedBounds);
- outAvailable.set(mAvailableBounds);
+ public void getMagnificationRegionLocked(@NonNull Region outMagnificationRegion) {
+ outMagnificationRegion.set(mMagnificationRegion);
}
public void updateMagnificationSpecLocked(MagnificationSpec spec) {
@@ -488,11 +484,12 @@
final int screenWidth = mTempPoint.x;
final int screenHeight = mTempPoint.y;
- mMagnifiedBounds.set(0, 0, 0, 0);
- mAvailableBounds.set(0, 0, screenWidth, screenHeight);
+ mMagnificationRegion.set(0, 0, 0, 0);
+ final Region availableBounds = mTempRegion1;
+ availableBounds.set(0, 0, screenWidth, screenHeight);
if (mCircularPath != null) {
- mAvailableBounds.setPath(mCircularPath, mAvailableBounds);
+ availableBounds.setPath(mCircularPath, availableBounds);
}
Region nonMagnifiedBounds = mTempRegion4;
@@ -526,21 +523,21 @@
(int) windowFrame.right, (int) windowFrame.bottom);
// Only update new regions
Region portionOfWindowAlreadyAccountedFor = mTempRegion3;
- portionOfWindowAlreadyAccountedFor.set(mMagnifiedBounds);
+ portionOfWindowAlreadyAccountedFor.set(mMagnificationRegion);
portionOfWindowAlreadyAccountedFor.op(nonMagnifiedBounds, Region.Op.UNION);
windowBounds.op(portionOfWindowAlreadyAccountedFor, Region.Op.DIFFERENCE);
if (mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
- mMagnifiedBounds.op(windowBounds, Region.Op.UNION);
- mMagnifiedBounds.op(mAvailableBounds, Region.Op.INTERSECT);
+ mMagnificationRegion.op(windowBounds, Region.Op.UNION);
+ mMagnificationRegion.op(availableBounds, Region.Op.INTERSECT);
} else {
nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
- mAvailableBounds.op(windowBounds, Region.Op.DIFFERENCE);
+ availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
}
// Update accounted bounds
Region accountedBounds = mTempRegion2;
- accountedBounds.set(mMagnifiedBounds);
+ accountedBounds.set(mMagnificationRegion);
accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
@@ -556,43 +553,36 @@
visibleWindows.clear();
- mMagnifiedBounds.op(mDrawBorderInset, mDrawBorderInset,
+ mMagnificationRegion.op(mDrawBorderInset, mDrawBorderInset,
screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
Region.Op.INTERSECT);
- final boolean magnifiedChanged = !mOldMagnifiedBounds.equals(mMagnifiedBounds);
- final boolean availableChanged = !mOldAvailableBounds.equals(mAvailableBounds);
- if (magnifiedChanged || availableChanged) {
- if (magnifiedChanged) {
- mWindow.setBounds(mMagnifiedBounds);
- Rect dirtyRect = mTempRect1;
- if (mFullRedrawNeeded) {
- mFullRedrawNeeded = false;
- dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
- screenWidth - mDrawBorderInset,
- screenHeight - mDrawBorderInset);
- mWindow.invalidate(dirtyRect);
- } else {
- Region dirtyRegion = mTempRegion3;
- dirtyRegion.set(mMagnifiedBounds);
- dirtyRegion.op(mOldMagnifiedBounds, Region.Op.UNION);
- dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
- dirtyRegion.getBounds(dirtyRect);
- mWindow.invalidate(dirtyRect);
- }
-
- mOldMagnifiedBounds.set(mMagnifiedBounds);
+ final boolean magnifiedChanged =
+ !mOldMagnificationRegion.equals(mMagnificationRegion);
+ if (magnifiedChanged) {
+ mWindow.setBounds(mMagnificationRegion);
+ final Rect dirtyRect = mTempRect1;
+ if (mFullRedrawNeeded) {
+ mFullRedrawNeeded = false;
+ dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
+ screenWidth - mDrawBorderInset,
+ screenHeight - mDrawBorderInset);
+ mWindow.invalidate(dirtyRect);
+ } else {
+ final Region dirtyRegion = mTempRegion3;
+ dirtyRegion.set(mMagnificationRegion);
+ dirtyRegion.op(mOldMagnificationRegion, Region.Op.UNION);
+ dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
+ dirtyRegion.getBounds(dirtyRect);
+ mWindow.invalidate(dirtyRect);
}
- if (availableChanged) {
- mOldAvailableBounds.set(mAvailableBounds);
- }
-
+ mOldMagnificationRegion.set(mMagnificationRegion);
final SomeArgs args = SomeArgs.obtain();
- args.arg1 = Region.obtain(mMagnifiedBounds);
- args.arg2 = Region.obtain(mAvailableBounds);
+ args.arg1 = Region.obtain(mMagnificationRegion);
mHandler.obtainMessage(
- MyHandler.MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED, args).sendToTarget();
+ MyHandler.MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED, args)
+ .sendToTarget();
}
}
@@ -616,14 +606,14 @@
public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
if (shown) {
mFullRedrawNeeded = true;
- mOldMagnifiedBounds.set(0, 0, 0, 0);
+ mOldMagnificationRegion.set(0, 0, 0, 0);
}
mWindow.setShown(shown, animate);
}
public void getMagnifiedFrameInContentCoordsLocked(Rect rect) {
MagnificationSpec spec = mMagnificationSpec;
- mMagnifiedBounds.getBounds(rect);
+ mMagnificationRegion.getBounds(rect);
rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
rect.scale(1.0f / spec.scale);
}
@@ -886,7 +876,7 @@
}
private class MyHandler extends Handler {
- public static final int MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED = 1;
+ public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1;
public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2;
public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4;
@@ -899,13 +889,11 @@
@Override
public void handleMessage(Message message) {
switch (message.what) {
- case MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED: {
+ case MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED: {
final SomeArgs args = (SomeArgs) message.obj;
final Region magnifiedBounds = (Region) args.arg1;
- final Region availableBounds = (Region) args.arg2;
- mCallbacks.onMagnifiedBoundsChanged(magnifiedBounds, availableBounds);
+ mCallbacks.onMagnificationRegionChanged(magnifiedBounds);
magnifiedBounds.recycle();
- availableBounds.recycle();
} break;
case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index cf415ff..6a20edb 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3625,8 +3625,7 @@
// disregarding font scale, which should remain set to
// the value of the previous configuration.
mTempConfiguration.setToDefaults();
- mTempConfiguration.fontScale = currentConfig.fontScale;
- mTempConfiguration.uiMode = currentConfig.uiMode;
+ mTempConfiguration.updateFrom(currentConfig);
computeScreenConfigurationLocked(mTempConfiguration);
if (currentConfig.diff(mTempConfiguration) != 0) {
mWaitingForConfig = true;
@@ -3689,11 +3688,15 @@
}
synchronized(mWindowMap) {
- mCurConfiguration = new Configuration(config);
if (mWaitingForConfig) {
mWaitingForConfig = false;
mLastFinishedFreezeSource = "new-config";
}
+ boolean configChanged = mCurConfiguration.diff(config) != 0;
+ if (!configChanged) {
+ return null;
+ }
+ mCurConfiguration = new Configuration(config);
return onConfigurationChanged();
}
}
@@ -8877,8 +8880,7 @@
boolean configChanged = updateOrientationFromAppTokensLocked(false);
mTempConfiguration.setToDefaults();
- mTempConfiguration.fontScale = mCurConfiguration.fontScale;
- mTempConfiguration.uiMode = mCurConfiguration.uiMode;
+ mTempConfiguration.updateFrom(mCurConfiguration);
computeScreenConfigurationLocked(mTempConfiguration);
configChanged |= mCurConfiguration.diff(mTempConfiguration) != 0;
@@ -10975,12 +10977,10 @@
}
@Override
- public void getMagnificationRegions(@NonNull Region outMagnified,
- @NonNull Region outAvailable) {
+ public void getMagnificationRegion(@NonNull Region magnificationRegion) {
synchronized (mWindowMap) {
if (mAccessibilityController != null) {
- mAccessibilityController.getMagnificationRegionsLocked(
- outMagnified, outAvailable);
+ mAccessibilityController.getMagnificationRegionLocked(magnificationRegion);
} else {
throw new IllegalStateException("Magnification callbacks not set!");
}
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 5c43659..183a370 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -27,8 +27,10 @@
#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/hardware.h>
+#include <hardware/power.h>
#include <suspend/autosuspend.h>
+#include <inttypes.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
@@ -47,6 +49,7 @@
static bool wakeup_init = false;
static sem_t wakeup_sem;
+extern struct power_module* gPowerModule;
static void wakeup_callback(bool success)
{
@@ -170,8 +173,122 @@
return mergedreasonpos - mergedreason;
}
+static jint getPlatformLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) {
+ int num_modes = -1;
+ char *output = (char*)env->GetDirectBufferAddress(outBuf), *offset = output;
+ int remaining = (int)env->GetDirectBufferCapacity(outBuf);
+ power_state_platform_sleep_state_t *list;
+ size_t *voter_list;
+ int total_added = -1;
+
+ if (outBuf == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", "null argument");
+ goto error;
+ }
+
+ if (!gPowerModule) {
+ ALOGE("%s: gPowerModule not loaded", POWER_HARDWARE_MODULE_ID);
+ goto error;
+ }
+
+ if (! (gPowerModule->get_platform_low_power_stats && gPowerModule->get_number_of_platform_modes
+ && gPowerModule->get_voter_list)) {
+ ALOGE("%s: Missing API", POWER_HARDWARE_MODULE_ID);
+ goto error;
+ }
+
+ if (gPowerModule->get_number_of_platform_modes) {
+ num_modes = gPowerModule->get_number_of_platform_modes(gPowerModule);
+ }
+
+ if (num_modes < 1) {
+ ALOGE("%s: Platform does not even have one low power mode", POWER_HARDWARE_MODULE_ID);
+ goto error;
+ }
+
+ list = (power_state_platform_sleep_state_t *)calloc(num_modes,
+ sizeof(power_state_platform_sleep_state_t));
+ if (!list) {
+ ALOGE("%s: power_state_platform_sleep_state_t allocation failed", POWER_HARDWARE_MODULE_ID);
+ goto error;
+ }
+
+ voter_list = (size_t *)calloc(num_modes, sizeof(*voter_list));
+ if (!voter_list) {
+ ALOGE("%s: voter_list allocation failed", POWER_HARDWARE_MODULE_ID);
+ goto err_free;
+ }
+
+ gPowerModule->get_voter_list(gPowerModule, voter_list);
+
+ for (int i = 0; i < num_modes; i++) {
+ list[i].voters = (power_state_voter_t *)calloc(voter_list[i],
+ sizeof(power_state_voter_t));
+ if (!list[i].voters) {
+ ALOGE("%s: voter_t allocation failed", POWER_HARDWARE_MODULE_ID);
+ goto err_free;
+ }
+ }
+
+ if (!gPowerModule->get_platform_low_power_stats(gPowerModule, list)) {
+ for (int i = 0; i < num_modes; i++) {
+ int added;
+
+ added = snprintf(offset, remaining, "%s_time=%" PRIu64 " %s_count=%" PRIu64 " ",
+ list[i].name, list[i].residency_in_msec_since_boot, list[i].name,
+ list[i].total_transitions);
+ if (added < 0) {
+ break;
+ }
+ if (added > remaining) {
+ added = remaining;
+ }
+ offset += added;
+ remaining -= added;
+ total_added += added;
+
+ for (unsigned int j = 0; j < list[i].number_of_voters; j++) {
+ added = snprintf(offset, remaining, "%s_time=%" PRIu64 " %s_count=%" PRIu64 " ",
+ list[i].voters[j].name,
+ list[i].voters[j].total_time_in_msec_voted_for_since_boot,
+ list[i].voters[j].name,
+ list[i].voters[j].total_number_of_times_voted_since_boot);
+ if (added < 0) {
+ break;
+ }
+ if (added > remaining) {
+ added = remaining;
+ }
+ offset += added;
+ remaining -= added;
+ total_added += added;
+ }
+
+ if (remaining <= 0) {
+ /* rewrite NULL character*/
+ offset--;
+ total_added--;
+ ALOGE("%s module: buffer not enough", POWER_HARDWARE_MODULE_ID);
+ break;
+ }
+ }
+ }
+ *offset = 0;
+ total_added += 1;
+
+err_free:
+ for (int i = 0; i < num_modes; i++) {
+ free(list[i].voters);
+ }
+ free(list);
+ free(voter_list);
+error:
+ return total_added;
+}
+
static const JNINativeMethod method_table[] = {
{ "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup },
+ { "getPlatformLowPowerStats", "(Ljava/nio/ByteBuffer;)I", (void*)getPlatformLowPowerStats },
};
int register_android_server_BatteryStatsService(JNIEnv *env)
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 2fdb8e2..cbbfda6a 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -48,7 +48,7 @@
// ----------------------------------------------------------------------------
static jobject gPowerManagerServiceObj;
-static struct power_module* gPowerModule;
+struct power_module* gPowerModule;
static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];