Merge "AnyMotionDetector holds wakelock until conclusive. Bug: 27821976" into nyc-dev
diff --git a/Android.mk b/Android.mk
index fc9c319..ae5d67e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -244,6 +244,8 @@
core/java/android/service/notification/IConditionListener.aidl \
core/java/android/service/notification/IConditionProvider.aidl \
core/java/android/service/vr/IVrListener.aidl \
+ core/java/android/service/vr/IVrManager.aidl \
+ core/java/android/service/vr/IVrStateCallbacks.aidl \
core/java/android/print/ILayoutResultCallback.aidl \
core/java/android/print/IPrinterDiscoveryObserver.aidl \
core/java/android/print/IPrintDocumentAdapter.aidl \
diff --git a/api/current.txt b/api/current.txt
index e11b389..501d6b6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4979,7 +4979,7 @@
field public int ledARGB;
field public int ledOffMS;
field public int ledOnMS;
- field public int number;
+ field public deprecated int number;
field public int priority;
field public android.app.Notification publicVersion;
field public android.net.Uri sound;
@@ -5072,7 +5072,7 @@
method public android.app.Notification.Builder setChronometerCountsDown(boolean);
method public android.app.Notification.Builder setColor(int);
method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
- method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
+ method public deprecated android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
method public android.app.Notification.Builder setContentText(java.lang.CharSequence);
method public android.app.Notification.Builder setContentTitle(java.lang.CharSequence);
@@ -5089,7 +5089,7 @@
method public android.app.Notification.Builder setLargeIcon(android.graphics.drawable.Icon);
method public android.app.Notification.Builder setLights(int, int, int);
method public android.app.Notification.Builder setLocalOnly(boolean);
- method public android.app.Notification.Builder setNumber(int);
+ method public deprecated android.app.Notification.Builder setNumber(int);
method public android.app.Notification.Builder setOngoing(boolean);
method public android.app.Notification.Builder setOnlyAlertOnce(boolean);
method public android.app.Notification.Builder setPriority(int);
@@ -46438,21 +46438,21 @@
ctor public DatePicker(android.content.Context, android.util.AttributeSet);
ctor public DatePicker(android.content.Context, android.util.AttributeSet, int);
ctor public DatePicker(android.content.Context, android.util.AttributeSet, int, int);
- method public android.widget.CalendarView getCalendarView();
- method public boolean getCalendarViewShown();
+ method public deprecated android.widget.CalendarView getCalendarView();
+ method public deprecated boolean getCalendarViewShown();
method public int getDayOfMonth();
method public int getFirstDayOfWeek();
method public long getMaxDate();
method public long getMinDate();
method public int getMonth();
- method public boolean getSpinnersShown();
+ method public deprecated boolean getSpinnersShown();
method public int getYear();
method public void init(int, int, int, android.widget.DatePicker.OnDateChangedListener);
- method public void setCalendarViewShown(boolean);
+ method public deprecated void setCalendarViewShown(boolean);
method public void setFirstDayOfWeek(int);
method public void setMaxDate(long);
method public void setMinDate(long);
- method public void setSpinnersShown(boolean);
+ method public deprecated void setSpinnersShown(boolean);
method public void updateDate(int, int, int);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 98f70e2..113c8bc 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5112,7 +5112,7 @@
field public int ledARGB;
field public int ledOffMS;
field public int ledOnMS;
- field public int number;
+ field public deprecated int number;
field public int priority;
field public android.app.Notification publicVersion;
field public android.net.Uri sound;
@@ -5205,7 +5205,7 @@
method public android.app.Notification.Builder setChronometerCountsDown(boolean);
method public android.app.Notification.Builder setColor(int);
method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
- method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
+ method public deprecated android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
method public android.app.Notification.Builder setContentText(java.lang.CharSequence);
method public android.app.Notification.Builder setContentTitle(java.lang.CharSequence);
@@ -5222,7 +5222,7 @@
method public android.app.Notification.Builder setLargeIcon(android.graphics.drawable.Icon);
method public android.app.Notification.Builder setLights(int, int, int);
method public android.app.Notification.Builder setLocalOnly(boolean);
- method public android.app.Notification.Builder setNumber(int);
+ method public deprecated android.app.Notification.Builder setNumber(int);
method public android.app.Notification.Builder setOngoing(boolean);
method public android.app.Notification.Builder setOnlyAlertOnce(boolean);
method public android.app.Notification.Builder setPriority(int);
@@ -49535,21 +49535,21 @@
ctor public DatePicker(android.content.Context, android.util.AttributeSet);
ctor public DatePicker(android.content.Context, android.util.AttributeSet, int);
ctor public DatePicker(android.content.Context, android.util.AttributeSet, int, int);
- method public android.widget.CalendarView getCalendarView();
- method public boolean getCalendarViewShown();
+ method public deprecated android.widget.CalendarView getCalendarView();
+ method public deprecated boolean getCalendarViewShown();
method public int getDayOfMonth();
method public int getFirstDayOfWeek();
method public long getMaxDate();
method public long getMinDate();
method public int getMonth();
- method public boolean getSpinnersShown();
+ method public deprecated boolean getSpinnersShown();
method public int getYear();
method public void init(int, int, int, android.widget.DatePicker.OnDateChangedListener);
- method public void setCalendarViewShown(boolean);
+ method public deprecated void setCalendarViewShown(boolean);
method public void setFirstDayOfWeek(int);
method public void setMaxDate(long);
method public void setMinDate(long);
- method public void setSpinnersShown(boolean);
+ method public deprecated void setSpinnersShown(boolean);
method public void updateDate(int, int, int);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 11abb4c..3fbac02 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4979,7 +4979,7 @@
field public int ledARGB;
field public int ledOffMS;
field public int ledOnMS;
- field public int number;
+ field public deprecated int number;
field public int priority;
field public android.app.Notification publicVersion;
field public android.net.Uri sound;
@@ -5072,7 +5072,7 @@
method public android.app.Notification.Builder setChronometerCountsDown(boolean);
method public android.app.Notification.Builder setColor(int);
method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
- method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
+ method public deprecated android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
method public android.app.Notification.Builder setContentText(java.lang.CharSequence);
method public android.app.Notification.Builder setContentTitle(java.lang.CharSequence);
@@ -5089,7 +5089,7 @@
method public android.app.Notification.Builder setLargeIcon(android.graphics.drawable.Icon);
method public android.app.Notification.Builder setLights(int, int, int);
method public android.app.Notification.Builder setLocalOnly(boolean);
- method public android.app.Notification.Builder setNumber(int);
+ method public deprecated android.app.Notification.Builder setNumber(int);
method public android.app.Notification.Builder setOngoing(boolean);
method public android.app.Notification.Builder setOnlyAlertOnce(boolean);
method public android.app.Notification.Builder setPriority(int);
@@ -46512,21 +46512,21 @@
ctor public DatePicker(android.content.Context, android.util.AttributeSet);
ctor public DatePicker(android.content.Context, android.util.AttributeSet, int);
ctor public DatePicker(android.content.Context, android.util.AttributeSet, int, int);
- method public android.widget.CalendarView getCalendarView();
- method public boolean getCalendarViewShown();
+ method public deprecated android.widget.CalendarView getCalendarView();
+ method public deprecated boolean getCalendarViewShown();
method public int getDayOfMonth();
method public int getFirstDayOfWeek();
method public long getMaxDate();
method public long getMinDate();
method public int getMonth();
- method public boolean getSpinnersShown();
+ method public deprecated boolean getSpinnersShown();
method public int getYear();
method public void init(int, int, int, android.widget.DatePicker.OnDateChangedListener);
- method public void setCalendarViewShown(boolean);
+ method public deprecated void setCalendarViewShown(boolean);
method public void setFirstDayOfWeek(int);
method public void setMaxDate(long);
method public void setMinDate(long);
- method public void setSpinnersShown(boolean);
+ method public deprecated void setSpinnersShown(boolean);
method public void updateDate(int, int, int);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8423de8..65e9f10 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -174,6 +174,9 @@
* <li>Notification of an ongoing countdown timer should be stamped with the timer's end time.
* </ul>
*
+ * For apps targeting {@link android.os.Build.VERSION_CODES#N} and above, this time is not shown
+ * anymore by default and must be opted into by using
+ * {@link android.app.Notification.Builder#setShowWhen(boolean)}
*/
public long when;
@@ -206,6 +209,8 @@
* {@link Notification.Builder} has displayed the number in the expanded notification view.
*
* If the number is 0 or negative, it is never shown.
+ *
+ * @deprecated this number is not shown anymore
*/
public int number;
@@ -2133,7 +2138,9 @@
if (toAdopt == null) {
mN = new Notification();
- mN.extras.putBoolean(EXTRA_SHOW_WHEN, true);
+ if (context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
+ mN.extras.putBoolean(EXTRA_SHOW_WHEN, true);
+ }
mN.priority = PRIORITY_DEFAULT;
mN.visibility = VISIBILITY_PRIVATE;
} else {
@@ -2183,8 +2190,10 @@
/**
* Add a timestamp pertaining to the notification (usually the time the event occurred).
- * It will be shown in the notification content view by default; use
- * {@link #setShowWhen(boolean) setShowWhen} to control this.
+ *
+ * For apps targeting {@link android.os.Build.VERSION_CODES#N} and above, this time is not
+ * shown anymore by default and must be opted into by using
+ * {@link android.app.Notification.Builder#setShowWhen(boolean)}
*
* @see Notification#when
*/
@@ -2196,6 +2205,8 @@
/**
* Control whether the timestamp set with {@link #setWhen(long) setWhen} is shown
* in the content view.
+ * For apps targeting {@link android.os.Build.VERSION_CODES#N} and above, this defaults to
+ * {@code false}. For earlier apps, the default is {@code true}.
*/
public Builder setShowWhen(boolean show) {
mN.extras.putBoolean(EXTRA_SHOW_WHEN, show);
@@ -2304,9 +2315,22 @@
}
/**
- * Set the third line of text in the platform notification template.
- * Don't use if you're also using {@link #setProgress(int, int, boolean)}; they occupy the
- * same location in the standard template.
+ * This provides some additional information that is displayed in the notification. No
+ * guarantees are given where exactly it is displayed.
+ *
+ * <p>This information should only be provided if it provides an essential
+ * benefit to the understanding of the notification. The more text you provide the
+ * less readable it becomes. For example, an email client should only provide the account
+ * name here if more than one email account has been added.</p>
+ *
+ * <p>As of {@link android.os.Build.VERSION_CODES#N} this information is displayed in the
+ * notification header area.
+ *
+ * On Android versions before {@link android.os.Build.VERSION_CODES#N}
+ * this will be shown in the third line of text in the platform notification template.
+ * You should not be using {@link #setProgress(int, int, boolean)} at the
+ * same time on those versions; they occupy the same place.
+ * </p>
*/
public Builder setSubText(CharSequence text) {
mN.extras.putCharSequence(EXTRA_SUB_TEXT, safeCharSequence(text));
@@ -2345,6 +2369,8 @@
* Set the large number at the right-hand side of the notification. This is
* equivalent to setContentInfo, although it might show the number in a different
* font size for readability.
+ *
+ * @deprecated this number is not shown anywhere anymore
*/
public Builder setNumber(int number) {
mN.number = number;
@@ -2356,6 +2382,10 @@
*
* The platform template will draw this on the last line of the notification, at the far
* right (to the right of a smallIcon if it has been placed there).
+ *
+ * @deprecated use {@link #setSubText(CharSequence)} instead to set a text in the header.
+ * For legacy apps targeting a version below {@link android.os.Build.VERSION_CODES#N} this
+ * field will still show up, but the subtext will take precedence.
*/
public Builder setContentInfo(CharSequence info) {
mN.extras.putCharSequence(EXTRA_INFO_TEXT, safeCharSequence(info));
@@ -3009,10 +3039,8 @@
contentView.setBoolean(R.id.notification_header, "setExpanded", false);
contentView.setTextViewText(R.id.app_name_text, null);
contentView.setViewVisibility(R.id.chronometer, View.GONE);
- contentView.setViewVisibility(R.id.header_sub_text, View.GONE);
- contentView.setViewVisibility(R.id.header_content_info, View.GONE);
- contentView.setViewVisibility(R.id.sub_text_divider, View.GONE);
- contentView.setViewVisibility(R.id.content_info_divider, View.GONE);
+ contentView.setViewVisibility(R.id.header_text, View.GONE);
+ contentView.setViewVisibility(R.id.header_text_divider, View.GONE);
contentView.setViewVisibility(R.id.time_divider, View.GONE);
contentView.setImageViewIcon(R.id.profile_badge, null);
contentView.setViewVisibility(R.id.profile_badge, View.GONE);
@@ -3112,39 +3140,12 @@
private void bindNotificationHeader(RemoteViews contentView) {
bindSmallIcon(contentView);
bindHeaderAppName(contentView);
- bindHeaderSubText(contentView);
- bindContentInfo(contentView);
+ bindHeaderText(contentView);
bindHeaderChronometerAndTime(contentView);
bindExpandButton(contentView);
bindProfileBadge(contentView);
}
- private void bindContentInfo(RemoteViews contentView) {
- boolean visible = false;
- if (mN.extras.getCharSequence(EXTRA_INFO_TEXT) != null) {
- contentView.setTextViewText(R.id.header_content_info,
- processLegacyText(mN.extras.getCharSequence(EXTRA_INFO_TEXT)));
- contentView.setViewVisibility(R.id.header_content_info, View.VISIBLE);
- visible = true;
- } else if (mN.number > 0) {
- final int tooBig = mContext.getResources().getInteger(
- R.integer.status_bar_notification_info_maxnum);
- if (mN.number > tooBig) {
- contentView.setTextViewText(R.id.header_content_info, processLegacyText(
- mContext.getResources().getString(
- R.string.status_bar_notification_info_overflow)));
- } else {
- contentView.setTextViewText(R.id.header_content_info,
- processLegacyText(String.valueOf(mN.number)));
- }
- contentView.setViewVisibility(R.id.header_content_info, View.VISIBLE);
- visible = true;
- }
- if (visible) {
- contentView.setViewVisibility(R.id.content_info_divider, View.VISIBLE);
- }
- }
-
private void bindExpandButton(RemoteViews contentView) {
contentView.setDrawableParameters(R.id.expand_button, false, -1, resolveContrastColor(),
PorterDuff.Mode.SRC_ATOP, -1);
@@ -3169,17 +3170,22 @@
}
}
- private void bindHeaderSubText(RemoteViews contentView) {
- CharSequence subText = mN.extras.getCharSequence(EXTRA_SUB_TEXT);
- if (subText == null && mStyle != null && mStyle.mSummaryTextSet
+ private void bindHeaderText(RemoteViews contentView) {
+ CharSequence headerText = mN.extras.getCharSequence(EXTRA_SUB_TEXT);
+ if (headerText == null && mStyle != null && mStyle.mSummaryTextSet
&& mStyle.hasSummaryInHeader()) {
- subText = mStyle.mSummaryText;
+ headerText = mStyle.mSummaryText;
}
- if (subText != null) {
+ if (headerText == null
+ && mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N
+ && mN.extras.getCharSequence(EXTRA_INFO_TEXT) != null) {
+ headerText = mN.extras.getCharSequence(EXTRA_INFO_TEXT);
+ }
+ if (headerText != null) {
// TODO: Remove the span entirely to only have the string with propper formating.
- contentView.setTextViewText(R.id.header_sub_text, processLegacyText(subText));
- contentView.setViewVisibility(R.id.header_sub_text, View.VISIBLE);
- contentView.setViewVisibility(R.id.sub_text_divider, View.VISIBLE);
+ contentView.setTextViewText(R.id.header_text, processLegacyText(headerText));
+ contentView.setViewVisibility(R.id.header_text, View.VISIBLE);
+ contentView.setViewVisibility(R.id.header_text_divider, View.VISIBLE);
}
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 720d3f7..f2e316c 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1178,23 +1178,7 @@
/** {@hide} */
public static File maybeTranslateEmulatedPathToInternal(File path) {
- final IMountService mountService = IMountService.Stub.asInterface(
- ServiceManager.getService("mount"));
- try {
- final VolumeInfo[] vols = mountService.getVolumes(0);
- for (VolumeInfo vol : vols) {
- if ((vol.getType() == VolumeInfo.TYPE_EMULATED
- || vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isMountedReadable()) {
- final File internalPath = FileUtils.rewriteAfterRename(vol.getPath(),
- vol.getInternalPath(), path);
- if (internalPath != null && internalPath.exists()) {
- return internalPath;
- }
- }
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ // Disabled now that FUSE has been replaced by sdcardfs
return path;
}
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
new file mode 100644
index 0000000..62ecab3
--- /dev/null
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.vr;
+
+import android.service.vr.IVrStateCallbacks;
+
+/** @hide */
+interface IVrManager {
+
+ /**
+ * Add a callback to be notified when VR mode state changes.
+ *
+ * @param cb the callback instance to add.
+ */
+ void registerListener(in IVrStateCallbacks cb);
+
+ /**
+ * Remove the callack from the current set of registered callbacks.
+ *
+ * @param cb the callback to remove.
+ */
+ void unregisterListener(in IVrStateCallbacks cb);
+
+ /**
+ * Return current VR mode state.
+ *
+ * @return {@code true} if VR mode is enabled.
+ */
+ boolean getVrModeState();
+
+}
+
diff --git a/core/java/android/service/vr/IVrStateCallbacks.aidl b/core/java/android/service/vr/IVrStateCallbacks.aidl
new file mode 100644
index 0000000..c4fdcd0
--- /dev/null
+++ b/core/java/android/service/vr/IVrStateCallbacks.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.vr;
+
+/** @hide */
+oneway interface IVrStateCallbacks {
+
+ void onVrStateChanged(in boolean enabled);
+
+}
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index cff9d8e..37da869 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -22,7 +22,6 @@
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.RemoteViews;
-import android.widget.TextView;
import java.util.ArrayList;
@@ -37,7 +36,7 @@
private final int mChildMinWidth;
private final int mContentEndMargin;
private View mAppName;
- private View mSubTextView;
+ private View mHeaderText;
private OnClickListener mExpandClickListener;
private HeaderTouchListener mTouchListener = new HeaderTouchListener();
private ImageView mExpandButton;
@@ -73,11 +72,10 @@
protected void onFinishInflate() {
super.onFinishInflate();
mAppName = findViewById(com.android.internal.R.id.app_name_text);
- mSubTextView = findViewById(com.android.internal.R.id.header_sub_text);
+ mHeaderText = findViewById(com.android.internal.R.id.header_text);
mExpandButton = (ImageView) findViewById(com.android.internal.R.id.expand_button);
mIcon = findViewById(com.android.internal.R.id.icon);
mProfileBadge = findViewById(com.android.internal.R.id.profile_badge);
- mInfo = findViewById(com.android.internal.R.id.header_content_info);
}
@Override
@@ -105,15 +103,7 @@
}
if (totalWidth > givenWidth) {
int overFlow = totalWidth - givenWidth;
- // We are overflowing, lets shrink the info first
- final int infoWidth = mInfo.getMeasuredWidth();
- if (mInfo.getVisibility() != GONE && infoWidth > mChildMinWidth) {
- int newSize = infoWidth - Math.min(infoWidth - mChildMinWidth, overFlow);
- int childWidthSpec = MeasureSpec.makeMeasureSpec(newSize, MeasureSpec.AT_MOST);
- mInfo.measure(childWidthSpec, wrapContentHeightSpec);
- overFlow -= infoWidth - newSize;
- }
- // still overflowing, lets shrink the app name now
+ // We are overflowing, lets shrink the app name first
final int appWidth = mAppName.getMeasuredWidth();
if (overFlow > 0 && mAppName.getVisibility() != GONE && appWidth > mChildMinWidth) {
int newSize = appWidth - Math.min(appWidth - mChildMinWidth, overFlow);
@@ -121,13 +111,13 @@
mAppName.measure(childWidthSpec, wrapContentHeightSpec);
overFlow -= appWidth - newSize;
}
- // still overflowing, finaly we shrink the subtext
- if (overFlow > 0 && mSubTextView.getVisibility() != GONE) {
+ // still overflowing, finaly we shrink the header text
+ if (overFlow > 0 && mHeaderText.getVisibility() != GONE) {
// we're still too big
- final int subTextWidth = mSubTextView.getMeasuredWidth();
- int newSize = Math.max(0, subTextWidth - overFlow);
+ final int textWidth = mHeaderText.getMeasuredWidth();
+ int newSize = Math.max(0, textWidth - overFlow);
int childWidthSpec = MeasureSpec.makeMeasureSpec(newSize, MeasureSpec.AT_MOST);
- mSubTextView.measure(childWidthSpec, wrapContentHeightSpec);
+ mHeaderText.measure(childWidthSpec, wrapContentHeightSpec);
}
}
setMeasuredDimension(givenWidth, givenHeight);
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 1536c29..d89c172 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -93,8 +93,12 @@
*/
public static final int ZORDER_BOTTOM = -1;
- private static final boolean USE_CLOSEGUARD
- = SystemProperties.getBoolean("log.closeguard.Animation", false);
+ // Use a preload holder to isolate static initialization into inner class, which allows
+ // Animation and its subclasses to be compile-time initialized.
+ private static class NoImagePreloadHolder {
+ public static final boolean USE_CLOSEGUARD
+ = SystemProperties.getBoolean("log.closeguard.Animation", false);
+ }
/**
* Set by {@link #getTransformation(long, Transformation)} when the animation ends.
@@ -859,7 +863,7 @@
if (!mStarted) {
fireAnimationStart();
mStarted = true;
- if (USE_CLOSEGUARD) {
+ if (NoImagePreloadHolder.USE_CLOSEGUARD) {
guard.open("cancel or detach or getTransformation");
}
}
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index e3357a7..0c5edc5 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -339,7 +339,9 @@
*
* @return {@code true} if the calendar view is shown
* @see #getCalendarView()
+ * @deprecated Not supported by Material-style {@code calendar} mode
*/
+ @Deprecated
public boolean getCalendarViewShown() {
return mDelegate.getCalendarViewShown();
}
@@ -347,13 +349,18 @@
/**
* Returns the {@link CalendarView} used by this picker.
* <p>
- * <strong>Note:</strong> This method returns {@code null} when the
+ * <strong>Note:</strong> This method throws an
+ * {@link UnsupportedOperationException} when the
* {@link android.R.styleable#DatePicker_datePickerMode} attribute is set
* to {@code calendar}.
*
* @return the calendar view
* @see #getCalendarViewShown()
+ * @deprecated Not supported by Material-style {@code calendar} mode
+ * @throws UnsupportedOperationException if called when the picker is
+ * displayed in {@code calendar} mode
*/
+ @Deprecated
public CalendarView getCalendarView() {
return mDelegate.getCalendarView();
}
@@ -367,7 +374,9 @@
*
* @param shown {@code true} to show the calendar view, {@code false} to
* hide it
+ * @deprecated Not supported by Material-style {@code calendar} mode
*/
+ @Deprecated
public void setCalendarViewShown(boolean shown) {
mDelegate.setCalendarViewShown(shown);
}
@@ -380,7 +389,9 @@
* to {@code calendar}.
*
* @return {@code true} if the spinners are shown
+ * @deprecated Not supported by Material-style {@code calendar} mode
*/
+ @Deprecated
public boolean getSpinnersShown() {
return mDelegate.getSpinnersShown();
}
@@ -394,7 +405,9 @@
*
* @param shown {@code true} to show the spinners, {@code false} to hide
* them
+ * @deprecated Not supported by Material-style {@code calendar} mode
*/
+ @Deprecated
public void setSpinnersShown(boolean shown) {
mDelegate.setSpinnersShown(shown);
}
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index e330de2..171a264 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -50,9 +50,12 @@
* Called when the device has finished going to sleep.
*
* @param why {@link #OFF_BECAUSE_OF_USER}, {@link #OFF_BECAUSE_OF_ADMIN},
- * or {@link #OFF_BECAUSE_OF_TIMEOUT}.
+ * or {@link #OFF_BECAUSE_OF_TIMEOUT}.
+ * @param cameraGestureTriggered whether the camera gesture was triggered between
+ * {@link #onStartedGoingToSleep} and this method; if it's been
+ * triggered, we shouldn't lock the device.
*/
- void onFinishedGoingToSleep(int reason);
+ void onFinishedGoingToSleep(int reason, boolean cameraGestureTriggered);
/**
* Called when the device has started waking up.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 88d75dd..9a2e39c7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2997,6 +2997,11 @@
<permission android:name="android.permission.BIND_VR_LISTENER_SERVICE"
android:protectionLevel="signature" />
+ <!-- Required to make calls to {@link android.service.vr.IVrManager}.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_VR_MANAGER"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to whitelist tasks during lock task mode
@hide <p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES"
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 0bbaa24..992e88e 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -42,7 +42,7 @@
android:singleLine="true"
/>
<TextView
- android:id="@+id/sub_text_divider"
+ android:id="@+id/header_text_divider"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Material.Notification.Info"
@@ -51,26 +51,7 @@
android:text="@string/notification_header_divider_symbol"
android:visibility="gone"/>
<TextView
- android:id="@+id/header_sub_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="@style/TextAppearance.Material.Notification.Info"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:visibility="gone"
- android:singleLine="true"/>
- <TextView
- android:id="@+id/content_info_divider"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="@style/TextAppearance.Material.Notification.Info"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:text="@string/notification_header_divider_symbol"
- android:singleLine="true"
- android:visibility="gone"/>
- <TextView
- android:id="@+id/header_content_info"
+ android:id="@+id/header_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Material.Notification.Info"
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2ce555a..2215bd4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2420,13 +2420,11 @@
<java-symbol type="string" name="notification_hidden_text" />
<java-symbol type="string" name="notification_hidden_by_policy_text" />
<java-symbol type="id" name="app_name_text" />
- <java-symbol type="id" name="header_sub_text" />
+ <java-symbol type="id" name="header_text" />
<java-symbol type="id" name="expand_button" />
<java-symbol type="id" name="notification_header" />
- <java-symbol type="id" name="header_content_info" />
<java-symbol type="id" name="time_divider" />
- <java-symbol type="id" name="sub_text_divider" />
- <java-symbol type="id" name="content_info_divider" />
+ <java-symbol type="id" name="header_text_divider" />
<java-symbol type="id" name="text_line_1" />
<java-symbol type="drawable" name="ic_expand_notification" />
<java-symbol type="drawable" name="ic_collapse_notification" />
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
index 1660e26..cf0643d 100644
--- a/packages/DocumentsUI/res/values/colors.xml
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -31,6 +31,7 @@
<color name="accent">@*android:color/accent_material_light</color>
<color name="accent_dark">@*android:color/accent_material_dark</color>
<color name="action_mode">@color/material_grey_400</color>
+ <color name="status_bar_color">@*android:color/material_blue_grey_950</color>
<color name="band_select_background">#88ffffff</color>
<color name="band_select_border">#44000000</color>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index b0996aa..9f09ebc 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -30,6 +30,7 @@
<item name="android:colorAccent">@color/accent</item>
<item name="colorActionMode">@color/action_mode</item>
<item name="android:queryBackground">@color/menu_search_background</item>
+ <item name="android:statusBarColor">@color/status_bar_color</item>
<item name="android:listDivider">@*android:drawable/list_divider_material</item>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 0d6ddf2..4ee37a5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -101,16 +101,6 @@
@CallSuper
@Override
public void onCreate(Bundle icicle) {
- // This flag is being set here as a result of the bug. When the flag was set in the
- // styles.xml keyboard was messing the layout of dialogs (create dir, rename).
- // Attempts were made to keep the flag in the main theme and to override it in the dialog
- // layout xml or to create separate style for dialog and assign it in styles.xml.
- // None of this brought successful results.
- // Setting the flag works here most probably because of the timing when it is set. Also the
- // setting might not affect the dialogs that are created in new windows or it affects them
- // in the different way that having this in the style.
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
-
// Record the time when onCreate is invoked for metric.
mStartTime = new Date().getTime();
@@ -140,7 +130,6 @@
mSearchManager = new SearchViewManager(this, icicle);
DocumentsToolbar toolbar = (DocumentsToolbar) findViewById(R.id.toolbar);
- Display.adjustToolbar(toolbar, this);
setActionBar(toolbar);
mNavigator = new NavigationView(
mDrawer,
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Display.java b/packages/DocumentsUI/src/com/android/documentsui/Display.java
index d46a3ea..8b13222 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Display.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Display.java
@@ -20,8 +20,6 @@
import android.content.Context;
import android.graphics.Point;
import android.util.TypedValue;
-import android.view.WindowManager;
-import android.widget.Toolbar;
/*
* Convenience class for getting display related attributes
@@ -47,41 +45,12 @@
* Returns action bar height in raw pixels.
*/
public static float actionBarHeight(Context context) {
- int height = 0;
+ int actionBarHeight = 0;
TypedValue tv = new TypedValue();
if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
- height = TypedValue.complexToDimensionPixelSize(tv.data,
+ actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,
context.getResources().getDisplayMetrics());
}
- return height;
- }
-
- /*
- * Returns status bar height in raw pixels.
- */
- private static int statusBarHeight(Context context) {
- int height = 0;
- int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen",
- "android");
- if (resourceId > 0) {
- height = context.getResources().getDimensionPixelSize(resourceId);
- }
- return height;
- }
-
- /*
- * Adjusts toolbar for the layout with translucent status bar. Increases the
- * height of the toolbar and adds padding at the top to accommodate status bar visible above
- * toolbar.
- */
- public static void adjustToolbar(Toolbar toolbar, Activity activity) {
- if ((activity.getWindow().getAttributes().flags
- & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
- int statusBarHeight = Display.statusBarHeight(activity);
- toolbar.getLayoutParams().height = (int) (Display.actionBarHeight(activity)
- + statusBarHeight);
- toolbar.setPadding(toolbar.getPaddingLeft(), statusBarHeight, toolbar.getPaddingRight(),
- toolbar.getPaddingBottom());
- }
+ return actionBarHeight;
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
index 7a4099a..14e6b69 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
@@ -84,7 +84,7 @@
View drawer = activity.findViewById(R.id.drawer_roots);
Toolbar toolbar = (Toolbar) activity.findViewById(R.id.roots_toolbar);
- Display.adjustToolbar(toolbar, activity);
+
drawer.getLayoutParams().width = calculateDrawerWidth(activity);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 630f359..155d618 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -490,24 +490,19 @@
@Override
public void onSelectionChanged() {
mSelectionManager.getSelection(mSelected);
- TypedValue color = new TypedValue();
if (mSelected.size() > 0) {
if (DEBUG) Log.d(TAG, "Maybe starting action mode.");
if (mActionMode == null) {
if (DEBUG) Log.d(TAG, "Yeah. Starting action mode.");
mActionMode = getActivity().startActionMode(this);
}
- getActivity().getTheme().resolveAttribute(R.attr.colorActionMode, color, true);
updateActionMenu();
} else {
if (DEBUG) Log.d(TAG, "Finishing action mode.");
if (mActionMode != null) {
mActionMode.finish();
}
- getActivity().getTheme().resolveAttribute(
- android.R.attr.colorPrimaryDark, color, true);
}
- getActivity().getWindow().setStatusBarColor(color.data);
if (mActionMode != null) {
final String title = Shared.getQuantityString(getActivity(),
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index c131fa5..7ca7614 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -463,7 +463,6 @@
.setContentTitle(title)
.setTicker(title)
.setContentText(name)
- .setContentInfo(percentageText)
.setProgress(info.max, info.progress, false)
.setOngoing(true)
.setContentIntent(infoPendingIntent)
@@ -958,7 +957,7 @@
.setDeleteIntent(newCancelIntent(context, info));
if (!TextUtils.isEmpty(info.name)) {
- builder.setContentInfo(info.name);
+ builder.setSubText(info.name);
}
Log.v(TAG, "Sending 'Share' notification for ID " + info.id + ": " + title);
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index c0a565db..e838191 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -329,7 +329,7 @@
*/
public void dismissChild(final View view, float velocity, boolean useAccelerateInterpolator) {
dismissChild(view, velocity, null /* endAction */, 0 /* delay */,
- useAccelerateInterpolator, 0 /* fixedDuration */);
+ useAccelerateInterpolator, 0 /* fixedDuration */, false /* isDismissAll */);
}
/**
@@ -341,17 +341,22 @@
* @param fixedDuration If not 0, this exact duration will be taken
*/
public void dismissChild(final View animView, float velocity, final Runnable endAction,
- long delay, boolean useAccelerateInterpolator, long fixedDuration) {
+ long delay, boolean useAccelerateInterpolator, long fixedDuration,
+ boolean isDismissAll) {
final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
float newPos;
boolean isLayoutRtl = animView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
- if (velocity < 0
- || (velocity == 0 && getTranslation(animView) < 0)
- // if we use the Menu to dismiss an item in landscape, animate up
- || (velocity == 0 && getTranslation(animView) == 0 && mSwipeDirection == Y)
- // if the language is rtl we prefer swiping to the left
- || (velocity == 0 && getTranslation(animView) == 0 && isLayoutRtl)) {
+ // if we use the Menu to dismiss an item in landscape, animate up
+ boolean animateUpForMenu = velocity == 0 && (getTranslation(animView) == 0 || isDismissAll)
+ && mSwipeDirection == Y;
+ // if the language is rtl we prefer swiping to the left
+ boolean animateLeftForRtl = velocity == 0 && (getTranslation(animView) == 0 || isDismissAll)
+ && isLayoutRtl;
+ boolean animateLeft = velocity < 0
+ || (velocity == 0 && getTranslation(animView) < 0 && !isDismissAll);
+
+ if (animateLeft || animateLeftForRtl || animateUpForMenu) {
newPos = -getSize(animView);
} else {
newPos = getSize(animView);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index d2c60ef..84d3599 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -115,9 +115,9 @@
}
@Override // Binder interface
- public void onFinishedGoingToSleep(int reason) {
+ public void onFinishedGoingToSleep(int reason, boolean cameraGestureTriggered) {
checkPermission();
- mKeyguardViewMediator.onFinishedGoingToSleep(reason);
+ mKeyguardViewMediator.onFinishedGoingToSleep(reason, cameraGestureTriggered);
}
@Override // Binder interface
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index a5dfc4b..e00bf6c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -747,7 +747,7 @@
notifyStartedGoingToSleep();
}
- public void onFinishedGoingToSleep(int why) {
+ public void onFinishedGoingToSleep(int why, boolean cameraGestureTriggered) {
if (DEBUG) Log.d(TAG, "onFinishedGoingToSleep(" + why + ")");
synchronized (this) {
mDeviceInteractive = false;
@@ -758,6 +758,16 @@
notifyFinishedGoingToSleep();
+ if (cameraGestureTriggered) {
+ Log.i(TAG, "Camera gesture was triggered, preventing Keyguard locking.");
+
+ // Just to make sure, make sure the device is awake.
+ mContext.getSystemService(PowerManager.class).wakeUp(SystemClock.uptimeMillis(),
+ "com.android.systemui:CAMERA_GESTURE_PREVENT_LOCK");
+ mPendingLock = false;
+ mPendingReset = false;
+ }
+
if (mPendingReset) {
resetStateLocked();
mPendingReset = false;
@@ -771,7 +781,7 @@
// We do not have timeout and power button instant lock setting for profile lock.
// So we use the personal setting if there is any. But if there is no device
// we need to make sure we lock it immediately when the screen is off.
- if (!mLockLater) {
+ if (!mLockLater && !cameraGestureTriggered) {
doKeyguardForChildProfilesLocked();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 8060e07..b1d9555 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -78,6 +78,9 @@
import com.android.systemui.recents.views.SystemBarScrimViews;
import com.android.systemui.statusbar.BaseStatusBar;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* The main Recents activity that is started from AlternateRecentsComponent.
*/
@@ -733,4 +736,20 @@
});
return true;
}
+
+ @Override
+ public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ super.dump(prefix, fd, writer, args);
+ String id = Integer.toHexString(System.identityHashCode(this));
+
+ writer.print(prefix); writer.print(TAG);
+ writer.print(" visible="); writer.print(mIsVisible ? "Y" : "N");
+ writer.print(" [0x"); writer.print(id); writer.print("]");
+ writer.println();
+
+ if (mRecentsView != null) {
+ mRecentsView.dump(prefix, writer);
+ }
+ EventBus.getDefault().dump(prefix, writer);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
index 0d56ae9..38ad1c7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
@@ -30,6 +30,7 @@
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
+import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@@ -652,19 +653,43 @@
/**
* @return a dump of the current state of the EventBus
*/
- public String dump() {
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(dumpInternal(prefix));
+ }
+
+ public String dumpInternal(String prefix) {
+ String innerPrefix = prefix + " ";
+ String innerInnerPrefix = innerPrefix + " ";
StringBuilder output = new StringBuilder();
+ output.append(prefix);
output.append("Registered class types:");
output.append("\n");
- for (Class<?> clz : mSubscriberTypeMap.keySet()) {
- output.append("\t");
+ ArrayList<Class<?>> subsciberTypes = new ArrayList<>(mSubscriberTypeMap.keySet());
+ Collections.sort(subsciberTypes, new Comparator<Class<?>>() {
+ @Override
+ public int compare(Class<?> o1, Class<?> o2) {
+ return o1.getSimpleName().compareTo(o2.getSimpleName());
+ }
+ });
+ for (int i = 0; i < subsciberTypes.size(); i++) {
+ Class<?> clz = subsciberTypes.get(i);
+ output.append(innerPrefix);
output.append(clz.getSimpleName());
output.append("\n");
}
+ output.append(prefix);
output.append("Event map:");
output.append("\n");
- for (Class<?> clz : mEventTypeMap.keySet()) {
- output.append("\t");
+ ArrayList<Class<?>> classes = new ArrayList<>(mEventTypeMap.keySet());
+ Collections.sort(classes, new Comparator<Class<?>>() {
+ @Override
+ public int compare(Class<?> o1, Class<?> o2) {
+ return o1.getSimpleName().compareTo(o2.getSimpleName());
+ }
+ });
+ for (int i = 0; i < classes.size(); i++) {
+ Class<?> clz = classes.get(i);
+ output.append(innerPrefix);
output.append(clz.getSimpleName());
output.append(" -> ");
output.append("\n");
@@ -673,7 +698,7 @@
Object subscriber = handler.subscriber.getReference();
if (subscriber != null) {
String id = Integer.toHexString(System.identityHashCode(subscriber));
- output.append("\t\t");
+ output.append(innerInnerPrefix);
output.append(subscriber.getClass().getSimpleName());
output.append(" [0x" + id + ", #" + handler.priority + "]");
output.append("\n");
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index e28612a..69d98af 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -243,4 +243,14 @@
public static float dpToPx(Resources res, float dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, res.getDisplayMetrics());
}
+
+ /**
+ * Returns a lightweight dump of a rect.
+ */
+ public static String dumpRect(Rect r) {
+ if (r == null) {
+ return "N:0,0-0,0";
+ }
+ return r.left + "," + r.top + "-" + r.right + "," + r.bottom;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 6668079..24eeaf2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -29,6 +29,7 @@
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Objects;
@@ -37,6 +38,9 @@
* A task represents the top most task in the system's task stack.
*/
public class Task {
+
+ public static final String TAG = "Task";
+
/* Task callbacks */
public interface TaskCallbacks {
/* Notifies when a task has been bound */
@@ -100,7 +104,8 @@
@Override
public String toString() {
- return "t" + id + ", s" + stackId + ", u" + userId;
+ return "id=" + id + " stackId=" + stackId + " user=" + userId + " lastActiveTime=" +
+ lastActiveTime;
}
private void updateHashCode() {
@@ -306,4 +311,13 @@
public String toString() {
return "[" + key.toString() + "] " + title;
}
+
+ public void dump(String prefix, PrintWriter writer) {
+ writer.print(prefix); writer.print(key);
+ if (affiliationTaskId != key.id) {
+ writer.print(" "); writer.print("affTaskId=" + affiliationTaskId);
+ }
+ writer.print(" "); writer.print(title);
+ writer.println();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index df3f56c..fbb5987 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -55,6 +55,7 @@
import com.android.systemui.recents.views.DropTarget;
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -208,6 +209,8 @@
*/
public class TaskStack {
+ private static final String TAG = "TaskStack";
+
/** Task stack callbacks */
public interface TaskStackCallbacks {
/**
@@ -725,7 +728,9 @@
/** Finds the task with the specified task id. */
public Task findTaskWithId(int taskId) {
ArrayList<Task> tasks = computeAllTasksList();
- for (Task task : tasks) {
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ Task task = tasks.get(i);
if (task.key.id == taskId) {
return task;
}
@@ -880,7 +885,10 @@
ArraySet<ComponentName> existingComponents = new ArraySet<>();
ArraySet<ComponentName> removedComponents = new ArraySet<>();
ArrayList<Task.TaskKey> taskKeys = getTaskKeys();
- for (Task.TaskKey t : taskKeys) {
+ int taskKeyCount = taskKeys.size();
+ for (int i = 0; i < taskKeyCount; i++) {
+ Task.TaskKey t = taskKeys.get(i);
+
// Skip if this doesn't apply to the current user
if (t.userId != userId) continue;
@@ -903,8 +911,10 @@
@Override
public String toString() {
String str = "Stack Tasks (" + mStackTaskList.size() + "):\n";
- for (Task t : mStackTaskList.getTasks()) {
- str += " " + t.toString() + "\n";
+ ArrayList<Task> tasks = mStackTaskList.getTasks();
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ str += " " + tasks.get(i).toString() + "\n";
}
return str;
}
@@ -921,4 +931,17 @@
}
return map;
}
+
+ public void dump(String prefix, PrintWriter writer) {
+ String innerPrefix = prefix + " ";
+
+ writer.print(prefix); writer.print(TAG);
+ writer.print(" numStackTasks="); writer.print(mStackTaskList.size());
+ writer.println();
+ ArrayList<Task> tasks = mStackTaskList.getTasks();
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ tasks.get(i).dump(innerPrefix, writer);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index ef81f9e..21a43d5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -74,6 +74,8 @@
import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.FlingAnimationUtils;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -83,6 +85,8 @@
*/
public class RecentsView extends FrameLayout {
+ private static final String TAG = "RecentsView";
+
private static final int DOCK_AREA_OVERLAY_TRANSITION_DURATION = 135;
private static final int DEFAULT_UPDATE_SCRIM_DURATION = 200;
private static final float DEFAULT_SCRIM_ALPHA = 0.33f;
@@ -758,4 +762,22 @@
top + mStackActionButton.getMeasuredHeight());
return actionButtonRect;
}
+
+ public void dump(String prefix, PrintWriter writer) {
+ String innerPrefix = prefix + " ";
+ String id = Integer.toHexString(System.identityHashCode(this));
+
+ writer.print(prefix); writer.print(TAG);
+ writer.print(" awaitingFirstLayout="); writer.print(mAwaitingFirstLayout ? "Y" : "N");
+ writer.print(" insets="); writer.print(Utilities.dumpRect(mSystemInsets));
+ writer.print(" [0x"); writer.print(id); writer.print("]");
+ writer.println();
+
+ if (mStack != null) {
+ mStack.dump(innerPrefix, writer);
+ }
+ if (mTaskStackView != null) {
+ mTaskStackView.dump(innerPrefix, writer);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index c16a9be4..b75a91e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -39,6 +39,7 @@
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
+import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -109,6 +110,8 @@
*/
public class TaskStackLayoutAlgorithm {
+ private static final String TAG = "TaskStackLayoutAlgorithm";
+
// The distribution of view bounds alpha
// XXX: This is a hack because you can currently set the max alpha to be > 1f
public static final float OUTLINE_ALPHA_MIN_VALUE = 0f;
@@ -684,7 +687,6 @@
}
/**
- *
* Returns the current stack state.
*/
public StackState getStackState() {
@@ -1157,4 +1159,44 @@
mBackOfStackTransform.visible = true;
mFrontOfStackTransform.visible = true;
}
-}
+
+ public void dump(String prefix, PrintWriter writer) {
+ String innerPrefix = prefix + " ";
+
+ writer.print(prefix); writer.print(TAG);
+ writer.write(" numStackTasks="); writer.write(mNumStackTasks);
+ writer.println();
+
+ writer.print(innerPrefix);
+ writer.print("insets="); writer.print(Utilities.dumpRect(mSystemInsets));
+ writer.print(" stack="); writer.print(Utilities.dumpRect(mStackRect));
+ writer.print(" task="); writer.print(Utilities.dumpRect(mTaskRect));
+ writer.print(" freeform="); writer.print(Utilities.dumpRect(mFreeformRect));
+ writer.print(" actionButton="); writer.print(Utilities.dumpRect(mStackActionButtonRect));
+ writer.println();
+
+ writer.print(innerPrefix);
+ writer.print("minScroll="); writer.print(mMinScrollP);
+ writer.print(" maxScroll="); writer.print(mMaxScrollP);
+ writer.print(" initialScroll="); writer.print(mInitialScrollP);
+ writer.println();
+
+ writer.print(innerPrefix);
+ writer.print("focusState="); writer.print(mFocusState);
+ writer.println();
+
+ if (mTaskIndexOverrideMap.size() > 0) {
+ for (int i = mTaskIndexOverrideMap.size() - 1; i >= 0; i--) {
+ int taskId = mTaskIndexOverrideMap.keyAt(i);
+ float x = mTaskIndexMap.get(taskId);
+ float overrideX = mTaskIndexOverrideMap.get(taskId, 0f);
+
+ writer.print(innerPrefix);
+ writer.print("taskId= "); writer.print(taskId);
+ writer.print(" x= "); writer.print(x);
+ writer.print(" overrideX= "); writer.print(overrideX);
+ writer.println();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 5416a48..13c8403 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -90,6 +90,7 @@
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
+import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -102,6 +103,8 @@
TaskStackLayoutAlgorithm.TaskStackLayoutAlgorithmCallbacks,
ViewPool.ViewPoolConsumer<TaskView, Task> {
+ private static final String TAG = "TaskStackView";
+
private final static String KEY_SAVED_STATE_SUPER = "saved_instance_state_super";
private final static String KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE =
"saved_instance_state_layout_focused_state";
@@ -2067,4 +2070,37 @@
mScreenPinningEnabled = ssp.getSystemSetting(getContext(),
Settings.System.LOCK_TO_APP_ENABLED) != 0;
}
+
+ public void dump(String prefix, PrintWriter writer) {
+ String innerPrefix = prefix + " ";
+ String id = Integer.toHexString(System.identityHashCode(this));
+
+ writer.print(prefix); writer.print(TAG);
+ writer.print(" hasDefRelayout=");
+ writer.print(mDeferredTaskViewLayoutAnimation != null ? "Y" : "N");
+ writer.print(" clipDirty="); writer.print(mTaskViewsClipDirty ? "Y" : "N");
+ writer.print(" awaitingFirstLayout="); writer.print(mAwaitingFirstLayout ? "Y" : "N");
+ writer.print(" initialState="); writer.print(mInitialState);
+ writer.print(" inMeasureLayout="); writer.print(mInMeasureLayout ? "Y" : "N");
+ writer.print(" enterAnimCompleted="); writer.print(mEnterAnimationComplete ? "Y" : "N");
+ writer.print(" touchExplorationOn="); writer.print(mTouchExplorationEnabled ? "Y" : "N");
+ writer.print(" screenPinningOn="); writer.print(mScreenPinningEnabled ? "Y" : "N");
+ writer.print(" numIgnoreTasks="); writer.print(mIgnoreTasks.size());
+ writer.print(" numViewPool="); writer.print(mViewPool.getViews().size());
+ writer.print(" stableStackBounds="); writer.print(Utilities.dumpRect(mStableStackBounds));
+ writer.print(" stackBounds="); writer.print(Utilities.dumpRect(mStackBounds));
+ writer.print(" stableWindow="); writer.print(Utilities.dumpRect(mStableWindowRect));
+ writer.print(" window="); writer.print(Utilities.dumpRect(mWindowRect));
+ writer.print(" [0x"); writer.print(id); writer.print("]");
+ writer.println();
+
+ if (mFocusedTask != null) {
+ writer.print(innerPrefix);
+ writer.print("Focused task: ");
+ mFocusedTask.dump(innerPrefix, writer);
+ }
+
+ mLayoutAlgorithm.dump(innerPrefix, writer);
+ mStackScroller.dump(innerPrefix, writer);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index 583fb88..19b3c94 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -30,6 +30,8 @@
import com.android.systemui.R;
import com.android.systemui.recents.misc.Utilities;
+import java.io.PrintWriter;
+
/* The scrolling logic for a TaskStackView */
public class TaskStackViewScroller {
@@ -246,4 +248,10 @@
mScroller.abortAnimation();
}
}
+
+ public void dump(String prefix, PrintWriter writer) {
+ writer.print(prefix); writer.print(TAG);
+ writer.print(" stackScroll:"); writer.print(mStackScrollP);
+ writer.println();
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 8102fae..29b6908 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -91,6 +91,7 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardHostView.OnDismissAction;
import com.android.systemui.DejankUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -100,6 +101,7 @@
import com.android.systemui.assist.AssistManager;
import com.android.systemui.recents.Recents;
import com.android.systemui.statusbar.NotificationData.Entry;
+import com.android.systemui.statusbar.NotificationGuts.OnGutsClosedListener;
import com.android.systemui.statusbar.phone.NavigationBarView;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -114,12 +116,12 @@
import java.util.Locale;
import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
-import static com.android.keyguard.KeyguardHostView.OnDismissAction;
public abstract class BaseStatusBar extends SystemUI implements
CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
- ExpandableNotificationRow.OnExpandClickListener {
+ ExpandableNotificationRow.OnExpandClickListener,
+ OnGutsClosedListener {
public static final String TAG = "StatusBar";
public static final boolean DEBUG = false;
public static final boolean MULTIUSER_DEBUG = false;
@@ -1010,6 +1012,7 @@
PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
row.setTag(sbn.getPackageName());
final NotificationGuts guts = row.getGuts();
+ guts.setClosedListener(this);
final String pkg = sbn.getPackageName();
String appname = pkg;
Drawable pkgicon = null;
@@ -1037,6 +1040,7 @@
settingsButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_INFO);
+ guts.resetFalsingCheck();
startAppNotificationSettingsActivity(pkg, appUidF);
}
});
@@ -1047,24 +1051,43 @@
row.findViewById(R.id.done).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- guts.saveImportance(sbn);
-
- int[] rowLocation = new int[2];
- int[] doneLocation = new int[2];
- row.getLocationOnScreen(rowLocation);
- v.getLocationOnScreen(doneLocation);
-
- final int centerX = v.getWidth() / 2;
- final int centerY = v.getHeight() / 2;
- final int x = doneLocation[0] - rowLocation[0] + centerX;
- final int y = doneLocation[1] - rowLocation[1] + centerY;
- dismissPopups(x, y);
+ // If the user has security enabled, show challenge if the setting is changed.
+ if (guts.hasImportanceChanged() && isLockscreenPublicMode() &&
+ (mState == StatusBarState.KEYGUARD
+ || mState == StatusBarState.SHADE_LOCKED)) {
+ OnDismissAction dismissAction = new OnDismissAction() {
+ @Override
+ public boolean onDismiss() {
+ saveImportanceCloseControls(sbn, row, guts, v);
+ return true;
+ }
+ };
+ onLockedNotificationImportanceChange(dismissAction);
+ } else {
+ saveImportanceCloseControls(sbn, row, guts, v);
+ }
}
});
-
guts.bindImportance(pmUser, sbn, row, mNotificationData.getImportance(sbn.getKey()));
}
+ private void saveImportanceCloseControls(StatusBarNotification sbn,
+ ExpandableNotificationRow row, NotificationGuts guts, View done) {
+ guts.resetFalsingCheck();
+ guts.saveImportance(sbn);
+
+ int[] rowLocation = new int[2];
+ int[] doneLocation = new int[2];
+ row.getLocationOnScreen(rowLocation);
+ done.getLocationOnScreen(doneLocation);
+
+ final int centerX = done.getWidth() / 2;
+ final int centerY = done.getHeight() / 2;
+ final int x = doneLocation[0] - rowLocation[0] + centerX;
+ final int y = doneLocation[1] - rowLocation[1] + centerY;
+ dismissPopups(x, y);
+ }
+
protected SwipeHelper.LongPressListener getNotificationLongClicker() {
return new SwipeHelper.LongPressListener() {
@Override
@@ -1119,7 +1142,8 @@
}
});
a.start();
- guts.setExposed(true);
+ guts.setExposed(true /* exposed */,
+ mState == StatusBarState.KEYGUARD /* needsFalsingProtection */);
row.closeRemoteInput();
mStackScroller.onHeightChanged(null, true /* needsAnimation */);
mNotificationGutsExposed = guts;
@@ -1147,31 +1171,7 @@
public void dismissPopups(int x, int y, boolean resetGear, boolean animate) {
if (mNotificationGutsExposed != null) {
- final NotificationGuts v = mNotificationGutsExposed;
- mNotificationGutsExposed = null;
-
- if (v.getWindowToken() == null) return;
- if (x == -1 || y == -1) {
- x = (v.getLeft() + v.getRight()) / 2;
- y = (v.getTop() + v.getHeight() / 2);
- }
- final double horz = Math.max(v.getWidth() - x, x);
- final double vert = Math.max(v.getHeight() - y, y);
- final float r = (float) Math.hypot(horz, vert);
- final Animator a = ViewAnimationUtils.createCircularReveal(v,
- x, y, r, 0);
- a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- a.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
- a.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- v.setVisibility(View.GONE);
- }
- });
- a.start();
- v.setExposed(false);
- mStackScroller.onHeightChanged(null, true /* needsAnimation */);
+ mNotificationGutsExposed.closeControls(x, y, true /* notify */);
}
if (resetGear) {
mStackScroller.resetExposedGearView(animate, true /* force */);
@@ -1179,6 +1179,12 @@
}
@Override
+ public void onGutsClosed(NotificationGuts guts) {
+ mStackScroller.onHeightChanged(null, true /* needsAnimation */);
+ mNotificationGutsExposed = null;
+ }
+
+ @Override
public void showRecentApps(boolean triggeredFromAltTab) {
int msg = MSG_SHOW_RECENT_APPS;
mHandler.removeMessages(msg);
@@ -1450,6 +1456,8 @@
}
}
+ protected void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {}
+
protected void onLockedRemoteInput(ExpandableNotificationRow row, View clickedView) {}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 45a24a0..3c464d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -16,28 +16,35 @@
package com.android.systemui.statusbar;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.app.INotificationManager;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.view.View;
+import android.view.ViewAnimationUtils;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
+import android.widget.RadioGroup;
import android.widget.SeekBar;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settingslib.Utils;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
import com.android.systemui.tuner.TunerService;
/**
@@ -46,6 +53,8 @@
public class NotificationGuts extends LinearLayout implements TunerService.Tunable {
public static final String SHOW_SLIDER = "show_importance_slider";
+ private static final long CLOSE_GUTS_DELAY = 8000;
+
private Drawable mBackground;
private int mClipTopAmount;
private int mActualHeight;
@@ -59,10 +68,35 @@
private RadioButton mSilent;
private RadioButton mReset;
+ private Handler mHandler;
+ private Runnable mFalsingCheck;
+ private boolean mNeedsFalsingProtection;
+ private OnGutsClosedListener mListener;
+
+ public interface OnGutsClosedListener {
+ public void onGutsClosed(NotificationGuts guts);
+ }
+
public NotificationGuts(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
TunerService.get(mContext).addTunable(this, SHOW_SLIDER);
+ mHandler = new Handler();
+ mFalsingCheck = new Runnable() {
+ @Override
+ public void run() {
+ if (mNeedsFalsingProtection && mExposed) {
+ closeControls(-1 /* x */, -1 /* y */, true /* notify */);
+ }
+ }
+ };
+ }
+
+ public void resetFalsingCheck() {
+ mHandler.removeCallbacks(mFalsingCheck);
+ if (mNeedsFalsingProtection && mExposed) {
+ mHandler.postDelayed(mFalsingCheck, CLOSE_GUTS_DELAY);
+ }
}
@Override
@@ -130,30 +164,23 @@
importanceSlider.setVisibility(View.VISIBLE);
importanceButtons.setVisibility(View.GONE);
} else {
- int userImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
+ mStartingImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
try {
- userImportance =
+ mStartingImportance =
mINotificationManager.getImportance(sbn.getPackageName(), sbn.getUid());
} catch (RemoteException e) {}
- bindToggles(importanceButtons, userImportance, systemApp);
+ bindToggles(importanceButtons, mStartingImportance, systemApp);
importanceButtons.setVisibility(View.VISIBLE);
importanceSlider.setVisibility(View.GONE);
}
}
+ public boolean hasImportanceChanged() {
+ return mStartingImportance != getSelectedImportance();
+ }
+
void saveImportance(final StatusBarNotification sbn) {
- int progress;
- if (mSeekBar!= null && mSeekBar.isShown()) {
- progress = mSeekBar.getProgress();
- } else {
- if (mBlock.isChecked()) {
- progress = NotificationListenerService.Ranking.IMPORTANCE_NONE;
- } else if (mSilent.isChecked()) {
- progress = NotificationListenerService.Ranking.IMPORTANCE_LOW;
- } else {
- progress = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
- }
- }
+ int progress = getSelectedImportance();
MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
progress - mStartingImportance);
try {
@@ -163,8 +190,29 @@
}
}
+ private int getSelectedImportance() {
+ if (mSeekBar!= null && mSeekBar.isShown()) {
+ return mSeekBar.getProgress();
+ } else {
+ if (mBlock.isChecked()) {
+ return NotificationListenerService.Ranking.IMPORTANCE_NONE;
+ } else if (mSilent.isChecked()) {
+ return NotificationListenerService.Ranking.IMPORTANCE_LOW;
+ } else {
+ return NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
+ }
+ }
+ }
+
private void bindToggles(final View importanceButtons, final int importance,
final boolean systemApp) {
+ ((RadioGroup) importanceButtons).setOnCheckedChangeListener(
+ new RadioGroup.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(RadioGroup group, int checkedId) {
+ resetFalsingCheck();
+ }
+ });
mBlock = (RadioButton) importanceButtons.findViewById(R.id.block_importance);
mSilent = (RadioButton) importanceButtons.findViewById(R.id.silent_importance);
mReset = (RadioButton) importanceButtons.findViewById(R.id.reset_importance);
@@ -198,6 +246,7 @@
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ resetFalsingCheck();
if (progress < minProgress) {
seekBar.setProgress(minProgress);
progress = minProgress;
@@ -210,7 +259,7 @@
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
- // no-op
+ resetFalsingCheck();
}
@Override
@@ -256,6 +305,38 @@
mSeekBar.setProgress(mStartingImportance);
}
+ public void closeControls(int x, int y, boolean notify) {
+ if (getWindowToken() == null) {
+ if (notify && mListener != null) {
+ mListener.onGutsClosed(this);
+ }
+ return;
+ }
+ if (x == -1 || y == -1) {
+ x = (getLeft() + getRight()) / 2;
+ y = (getTop() + getHeight() / 2);
+ }
+ final double horz = Math.max(getWidth() - x, x);
+ final double vert = Math.max(getHeight() - y, y);
+ final float r = (float) Math.hypot(horz, vert);
+ final Animator a = ViewAnimationUtils.createCircularReveal(this,
+ x, y, r, 0);
+ a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ a.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+ a.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ setVisibility(View.GONE);
+ }
+ });
+ a.start();
+ setExposed(false, mNeedsFalsingProtection);
+ if (notify && mListener != null) {
+ mListener.onGutsClosed(this);
+ }
+ }
+
public void setActualHeight(int actualHeight) {
mActualHeight = actualHeight;
invalidate();
@@ -277,8 +358,18 @@
return false;
}
- public void setExposed(boolean exposed) {
+ public void setClosedListener(OnGutsClosedListener listener) {
+ mListener = listener;
+ }
+
+ public void setExposed(boolean exposed, boolean needsFalsingProtection) {
mExposed = exposed;
+ mNeedsFalsingProtection = needsFalsingProtection;
+ if (mExposed && mNeedsFalsingProtection) {
+ resetFalsingCheck();
+ } else {
+ mHandler.removeCallbacks(mFalsingCheck);
+ }
}
public boolean areGutsExposed() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
index c70aad2..06d79a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
@@ -131,11 +131,8 @@
mComparators.add(HeaderProcessor.forTextView(mRow,
com.android.internal.R.id.app_name_text));
mComparators.add(HeaderProcessor.forTextView(mRow,
- com.android.internal.R.id.header_sub_text));
- mComparators.add(HeaderProcessor.forTextView(mRow,
- com.android.internal.R.id.header_content_info));
- mDividers.add(com.android.internal.R.id.sub_text_divider);
- mDividers.add(com.android.internal.R.id.content_info_divider);
+ com.android.internal.R.id.header_text));
+ mDividers.add(com.android.internal.R.id.header_text_divider);
mDividers.add(com.android.internal.R.id.time_divider);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 32a6f16..bf58592 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -4197,6 +4197,12 @@
}
@Override
+ public void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {
+ mLeaveOpenOnKeyguardHide = true;
+ dismissKeyguardThenExecute(dismissAction, true /* afterKeyguardGone */);
+ }
+
+ @Override
protected void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
mLeaveOpenOnKeyguardHide = true;
showBouncer();
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 46a49ee..fa37e22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -918,7 +918,7 @@
int positionInLinearLayout = getPositionInLinearLayout(v);
int targetScroll = positionInLinearLayout + expandableView.getActualHeight() +
- mBottomInset - getHeight() + getTopPadding();
+ getImeInset() - getHeight() + getTopPadding();
if (mOwnScrollY < targetScroll) {
mScroller.startScroll(mScrollX, mOwnScrollY, 0, targetScroll - mOwnScrollY);
mDontReportNextOverScroll = true;
@@ -928,8 +928,7 @@
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- mBottomInset = Math.max(0, insets.getSystemWindowInsetBottom()
- - (getRootView().getHeight() - getHeight()));
+ mBottomInset = insets.getSystemWindowInsetBottom();
int range = getScrollRange();
if (mOwnScrollY > range) {
@@ -987,7 +986,8 @@
}
public void dismissViewAnimated(View child, Runnable endRunnable, int delay, long duration) {
- mSwipeHelper.dismissChild(child, 0, endRunnable, delay, true, duration);
+ mSwipeHelper.dismissChild(child, 0, endRunnable, delay, true, duration,
+ true /* isDismissAll */);
}
public void snapViewIfNeeded(View child) {
@@ -1498,23 +1498,17 @@
}
private int getScrollRange() {
- int scrollRange = 0;
- ExpandableView firstChild = (ExpandableView) getFirstChildNotGone();
- if (firstChild != null) {
- int contentHeight = getContentHeight();
- scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight + mBottomStackPeekSize
- + mBottomStackSlowDownHeight);
- if (scrollRange > 0) {
- int firstChildMaxExpandHeight = getMaxExpandHeight(firstChild);
- // We want to at least be able collapse the first item and not ending in a weird
- // end state.
- scrollRange = Math.max(scrollRange, firstChildMaxExpandHeight
- - firstChild.getMinHeight());
- }
- }
- int imeOverlap = Math.max(0,
- getContentHeight() - (getHeight() - mBottomInset));
- return scrollRange + imeOverlap;
+ int contentHeight = getContentHeight();
+ int scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight + mBottomStackPeekSize
+ + mBottomStackSlowDownHeight);
+ int imeInset = getImeInset();
+ scrollRange += Math.min(imeInset, Math.max(0,
+ getContentHeight() - (getHeight() - imeInset)));
+ return scrollRange;
+ }
+
+ private int getImeInset() {
+ return Math.max(0, mBottomInset - (getRootView().getHeight() - getHeight()));
}
/**
@@ -3201,9 +3195,6 @@
disableClipOptimization();
}
handleDismissAllClipping();
- if (mCurrIconRow != null && mCurrIconRow.isVisible()) {
- mCurrIconRow.getNotificationParent().animateTranslateNotification(0 /* left target */);
- }
}
private void handleDismissAllClipping() {
@@ -3463,8 +3454,10 @@
}
private class NotificationSwipeHelper extends SwipeHelper {
- private static final long GEAR_SHOW_DELAY = 60;
+ private static final long SHOW_GEAR_DELAY = 60;
+ private static final long COVER_GEAR_DELAY = 4000;
private CheckForDrag mCheckForDrag;
+ private Runnable mFalsingCheck;
private Handler mHandler;
private boolean mGearSnappedTo;
private boolean mGearSnappedOnLeft;
@@ -3472,6 +3465,12 @@
public NotificationSwipeHelper(int swipeDirection, Callback callback, Context context) {
super(swipeDirection, callback, context);
mHandler = new Handler();
+ mFalsingCheck = new Runnable() {
+ @Override
+ public void run() {
+ resetExposedGearView(true /* animate */, true /* force */);
+ }
+ };
}
@Override
@@ -3486,6 +3485,7 @@
}
mCheckForDrag = null;
mCurrIconRow = null;
+ mHandler.removeCallbacks(mFalsingCheck);
// Slide back any notifications that might be showing a gear
resetExposedGearView(true /* animate */, false /* force */);
@@ -3499,6 +3499,8 @@
@Override
public void onMoveUpdate(View view, float translation, float delta) {
+ mHandler.removeCallbacks(mFalsingCheck);
+
if (mCurrIconRow != null) {
mCurrIconRow.setSnapping(false); // If we're moving, we're not snapping.
@@ -3624,6 +3626,12 @@
setSnappedToGear(true);
}
onDragCancelled(animView);
+
+ // If we're on the lockscreen we want to false this.
+ if (mPhoneStatusBar.getBarState() == StatusBarState.KEYGUARD) {
+ mHandler.removeCallbacks(mFalsingCheck);
+ mHandler.postDelayed(mFalsingCheck, COVER_GEAR_DELAY);
+ }
super.snapChild(animView, target, velocity);
}
@@ -3646,10 +3654,7 @@
@Override
public Animator getViewTranslationAnimator(View v, float target,
AnimatorUpdateListener listener) {
- if (mDismissAllInProgress) {
- // When dismissing all, we translate the entire view instead.
- return super.getViewTranslationAnimator(v, target, listener);
- } else if (v instanceof ExpandableNotificationRow) {
+ if (v instanceof ExpandableNotificationRow) {
return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener);
} else {
return super.getViewTranslationAnimator(v, target, listener);
@@ -3658,22 +3663,12 @@
@Override
public void setTranslation(View v, float translate) {
- if (mDismissAllInProgress) {
- // When dismissing all, we translate the entire view instead.
- super.setTranslation(v, translate);
- } else {
- ((ExpandableView) v).setTranslation(translate);
- }
+ ((ExpandableView) v).setTranslation(translate);
}
@Override
public float getTranslation(View v) {
- if (mDismissAllInProgress) {
- // When dismissing all, we translate the entire view instead.
- return super.getTranslation(v);
- } else {
- return ((ExpandableView) v).getTranslation();
- }
+ return ((ExpandableView) v).getTranslation();
}
public void closeControlsIfOutsideTouch(MotionEvent ev) {
@@ -3740,7 +3735,7 @@
private void checkForDrag() {
if (mCheckForDrag == null || !mHandler.hasCallbacks(mCheckForDrag)) {
mCheckForDrag = new CheckForDrag();
- mHandler.postDelayed(mCheckForDrag, GEAR_SHOW_DELAY);
+ mHandler.postDelayed(mCheckForDrag, SHOW_GEAR_DELAY);
}
}
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index d6575e8..aa98648 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -34,6 +34,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Settings;
+import android.util.MutableBoolean;
import android.util.Slog;
import android.view.KeyEvent;
@@ -251,7 +252,8 @@
return isCameraLaunchEnabled(resources) || isCameraDoubleTapPowerEnabled(resources);
}
- public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive) {
+ public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive,
+ MutableBoolean outLaunched) {
boolean launched = false;
boolean intercept = false;
long doubleTapInterval;
@@ -276,6 +278,7 @@
}
}
MetricsLogger.histogram(mContext, "power_double_tap_interval", (int) doubleTapInterval);
+ outLaunched.value = launched;
return intercept && launched;
}
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index ed16af51..ab0f55e 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -254,7 +254,7 @@
com.android.internal.R.color.system_notification_accent_color))
.setContentTitle(title)
.setContentText(message)
- .setContentInfo(detail)
+ .setSubText(detail)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setContentIntent(intent)
.build();
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 7b134ca..7ba030f 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -107,6 +107,7 @@
private static final int FINGERPRINT_ACQUIRED_GOOD = 0;
private final String mKeyguardPackage;
private int mCurrentUserId = UserHandle.USER_CURRENT;
+ private int mUserIdForRemove = UserHandle.USER_NULL;
Handler mHandler = new Handler() {
@Override
@@ -205,10 +206,12 @@
protected void handleRemoved(long deviceId, int fingerId, int groupId) {
final ClientMonitor client = mRemoveClient;
if (fingerId != 0) {
- removeTemplateForUser(mRemoveClient, fingerId);
+ removeTemplateForUser(mUserIdForRemove, fingerId);
+ } else {
+ mUserIdForRemove = UserHandle.USER_NULL;
}
if (client != null && client.sendRemoved(fingerId, groupId)) {
- removeClient(mRemoveClient);
+ removeClient(client);
}
}
@@ -325,8 +328,8 @@
return false;
}
- private void removeTemplateForUser(ClientMonitor clientMonitor, int fingerId) {
- mFingerprintUtils.removeFingerprintIdForUser(mContext, fingerId, clientMonitor.userId);
+ private void removeTemplateForUser(int userId, int fingerId) {
+ mFingerprintUtils.removeFingerprintIdForUser(mContext, fingerId, userId);
}
private void addTemplateForUser(ClientMonitor clientMonitor, int fingerId) {
@@ -488,6 +491,7 @@
stopPendingOperations(true);
mRemoveClient = new ClientMonitor(token, receiver, userId, restricted, token.toString());
+ mUserIdForRemove = mCurrentUserId;
// The fingerprint template ids will be removed when we get confirmation from the HAL
try {
final int result = daemon.remove(fingerId, userId);
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 257c7da..5953dde 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -18,12 +18,17 @@
import com.android.server.SystemService;
import com.android.server.vr.VrManagerInternal;
+import com.android.server.vr.VrManagerService;
import com.android.server.vr.VrStateListener;
import android.content.Context;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Message;
+import android.os.RemoteException;
import android.os.Trace;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
import android.util.Slog;
public class LightsService extends SystemService {
@@ -164,13 +169,19 @@
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_SYSTEM_SERVICES_READY) {
- getLocalService(VrManagerInternal.class).registerListener(mVrStateListener);
+ IVrManager vrManager =
+ (IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);
+ try {
+ vrManager.registerListener(mVrStateCallbacks);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+ }
}
}
- private final VrStateListener mVrStateListener = new VrStateListener() {
+ private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
@Override
- public void onVrStateChanged(boolean enabled) {
+ public void onVrStateChanged(boolean enabled) throws RemoteException {
LightImpl l = mLights[LightsManager.LIGHT_ID_BACKLIGHT];
if (enabled) {
if (DEBUG) Slog.v(TAG, "VR mode enabled, setting brightness to low persistence");
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index a0752aa..97c0cf1 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -107,6 +107,7 @@
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
+import android.util.MutableBoolean;
import android.util.Slog;
import android.util.SparseArray;
import android.util.LongSparseArray;
@@ -396,6 +397,8 @@
volatile boolean mBeganFromNonInteractive;
volatile int mPowerKeyPressCounter;
volatile boolean mEndCallKeyHandled;
+ volatile boolean mCameraGestureTriggeredDuringGoingToSleep;
+ volatile boolean mGoingToSleep;
boolean mRecentsVisible;
int mRecentAppsHeldModifiers;
@@ -685,6 +688,7 @@
= new LogDecelerateInterpolator(100, 0);
private boolean mForceWindowDrawsStatusBarBackground;
+ private final MutableBoolean mTmpBoolean = new MutableBoolean(false);
private static final int MSG_ENABLE_POINTER_LOCATION = 1;
private static final int MSG_DISABLE_POINTER_LOCATION = 2;
@@ -1032,7 +1036,11 @@
GestureLauncherService.class);
boolean gesturedServiceIntercepted = false;
if (gestureService != null) {
- gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive);
+ gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,
+ mTmpBoolean);
+ if (mTmpBoolean.value && mGoingToSleep) {
+ mCameraGestureTriggeredDuringGoingToSleep = true;
+ }
}
// If the power key has still not yet been handled, then detect short
@@ -5954,6 +5962,8 @@
@Override
public void startedGoingToSleep(int why) {
if (DEBUG_WAKEUP) Slog.i(TAG, "Started going to sleep... (why=" + why + ")");
+ mCameraGestureTriggeredDuringGoingToSleep = false;
+ mGoingToSleep = true;
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onStartedGoingToSleep(why);
}
@@ -5966,6 +5976,8 @@
if (DEBUG_WAKEUP) Slog.i(TAG, "Finished going to sleep... (why=" + why + ")");
MetricsLogger.histogram(mContext, "screen_timeout", mLockScreenTimeout / 1000);
+ mGoingToSleep = false;
+
// We must get this work done here because the power manager will drop
// the wake lock and let the system suspend once this function returns.
synchronized (mLock) {
@@ -5975,8 +5987,10 @@
updateLockScreenTimeout();
}
if (mKeyguardDelegate != null) {
- mKeyguardDelegate.onFinishedGoingToSleep(why);
+ mKeyguardDelegate.onFinishedGoingToSleep(why,
+ mCameraGestureTriggeredDuringGoingToSleep);
}
+ mCameraGestureTriggeredDuringGoingToSleep = false;
}
// Called on the PowerManager's Notifier thread.
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 8d296d5..52e5880 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -294,9 +294,9 @@
mKeyguardState.interactiveState = INTERACTIVE_STATE_GOING_TO_SLEEP;
}
- public void onFinishedGoingToSleep(int why) {
+ public void onFinishedGoingToSleep(int why, boolean cameraGestureTriggered) {
if (mKeyguardService != null) {
- mKeyguardService.onFinishedGoingToSleep(why);
+ mKeyguardService.onFinishedGoingToSleep(why, cameraGestureTriggered);
}
mKeyguardState.interactiveState = INTERACTIVE_STATE_SLEEP;
}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index 429b188..dacdec0 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -117,9 +117,9 @@
}
@Override
- public void onFinishedGoingToSleep(int reason) {
+ public void onFinishedGoingToSleep(int reason, boolean cameraGestureTriggered) {
try {
- mService.onFinishedGoingToSleep(reason);
+ mService.onFinishedGoingToSleep(reason, cameraGestureTriggered);
} catch (RemoteException e) {
Slog.w(TAG , "Remote Exception", e);
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 7570960..8cd536d 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -53,6 +53,8 @@
import android.provider.Settings.Secure;
import android.provider.Settings.SettingNotFoundException;
import android.service.dreams.DreamManagerInternal;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseIntArray;
@@ -72,6 +74,7 @@
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
import com.android.server.vr.VrManagerInternal;
+import com.android.server.vr.VrManagerService;
import com.android.server.vr.VrStateListener;
import libcore.util.Objects;
@@ -658,7 +661,13 @@
resolver.registerContentObserver(Settings.Secure.getUriFor(
Secure.BRIGHTNESS_USE_TWILIGHT),
false, mSettingsObserver, UserHandle.USER_ALL);
- getLocalService(VrManagerInternal.class).registerListener(mVrStateListener);
+ IVrManager vrManager =
+ (IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);
+ try {
+ vrManager.registerListener(mVrStateCallbacks);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+ }
// Go.
readConfigurationLocked();
updateSettingsLocked();
@@ -3007,7 +3016,7 @@
}
}
- private final VrStateListener mVrStateListener = new VrStateListener() {
+ private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
@Override
public void onVrStateChanged(boolean enabled) {
powerHintInternal(POWER_HINT_VR_MODE, enabled ? 1 : 0);
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 93bb9d7..1bbb9f5 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -31,13 +31,6 @@
public static final int NO_ERROR = 0;
/**
- * Return current VR mode state.
- *
- * @return {@code true} if VR mode is enabled.
- */
- public abstract boolean isInVrMode();
-
- /**
* Return {@code true} if the given package is the currently bound VrListenerService for the
* given user.
*
@@ -59,22 +52,6 @@
public abstract void setVrMode(boolean enabled, @NonNull ComponentName packageName,
int userId, @NonNull ComponentName calling);
- /**
- * Add a listener for VR mode state changes.
- * <p>
- * This listener will immediately be called with the current VR mode state.
- * </p>
- * @param listener the listener instance to add.
- */
- public abstract void registerListener(@NonNull VrStateListener listener);
-
- /**
- * Remove the listener from the current set of listeners.
- *
- * @param listener the listener to remove.
- */
- public abstract void unregisterListener(@NonNull VrStateListener listener);
-
/**
* Return NO_ERROR if the given package is installed on the device and enabled as a
* VrListenerService for the given current user, or a negative error code indicating a failure.
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index c572e76..e6e5a2d 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -15,6 +15,7 @@
*/
package com.android.server.vr;
+import android.Manifest;
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.annotation.NonNull;
@@ -29,11 +30,15 @@
import android.os.IBinder;
import android.os.IInterface;
import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.service.vr.IVrListener;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
import android.service.vr.VrListenerService;
import android.util.ArraySet;
import android.util.Slog;
@@ -46,6 +51,7 @@
import com.android.server.utils.ManagedApplicationService.BinderChecker;
import java.lang.StringBuilder;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
@@ -75,6 +81,8 @@
public static final String TAG = "VrManagerService";
+ public static final String VR_MANAGER_BINDER_SERVICE = "vrmanager";
+
private static native void initializeNative();
private static native void setVrModeNative(boolean enabled);
@@ -84,7 +92,6 @@
// State protected by mLock
private boolean mVrModeEnabled;
- private final Set<VrStateListener> mListeners = new ArraySet<>();
private EnabledComponentsObserver mComponentObserver;
private ManagedApplicationService mCurrentVrService;
private Context mContext;
@@ -92,10 +99,37 @@
private int mCurrentVrModeUser;
private boolean mWasDefaultGranted;
private boolean mGuard;
+ private final RemoteCallbackList<IVrStateCallbacks> mRemoteCallbacks =
+ new RemoteCallbackList<>();
private final ArraySet<String> mPreviousToggledListenerSettings = new ArraySet<>();
private String mPreviousNotificationPolicyAccessPackage;
private String mPreviousManageOverlayPackage;
+ private static final int MSG_VR_STATE_CHANGE = 0;
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ case MSG_VR_STATE_CHANGE : {
+ boolean state = (msg.arg1 == 1);
+ int i = mRemoteCallbacks.beginBroadcast();
+ while (i > 0) {
+ i--;
+ try {
+ mRemoteCallbacks.getBroadcastItem(i).onVrStateChanged(state);
+ } catch (RemoteException e) {
+ // Noop
+ }
+ }
+ mRemoteCallbacks.finishBroadcast();
+ } break;
+ default :
+ throw new IllegalStateException("Unknown message type: " + msg.what);
+ }
+ }
+ };
+
private static final BinderChecker sBinderChecker = new BinderChecker() {
@Override
public IInterface asInterface(IBinder binder) {
@@ -125,16 +159,47 @@
}
}
+ private final IVrManager mVrManager = new IVrManager.Stub() {
+
+ @Override
+ public void registerListener(IVrStateCallbacks cb) {
+ enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER);
+ if (cb == null) {
+ throw new IllegalArgumentException("Callback binder object is null.");
+ }
+
+ VrManagerService.this.addStateCallback(cb);
+ }
+
+ @Override
+ public void unregisterListener(IVrStateCallbacks cb) {
+ enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER);
+ if (cb == null) {
+ throw new IllegalArgumentException("Callback binder object is null.");
+ }
+
+ VrManagerService.this.removeStateCallback(cb);
+ }
+
+ @Override
+ public boolean getVrModeState() {
+ return VrManagerService.this.getVrMode();
+ }
+
+ };
+
+ private void enforceCallerPermission(String permission) {
+ if (mContext.checkCallingOrSelfPermission(permission)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Caller does not hold the permission " + permission);
+ }
+ }
+
/**
* Implementation of VrManagerInternal. Callable only from system services.
*/
private final class LocalService extends VrManagerInternal {
@Override
- public boolean isInVrMode() {
- return VrManagerService.this.getVrMode();
- }
-
- @Override
public void setVrMode(boolean enabled, ComponentName packageName, int userId,
ComponentName callingPackage) {
VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage);
@@ -146,16 +211,6 @@
}
@Override
- public void registerListener(VrStateListener listener) {
- VrManagerService.this.addListener(listener);
- }
-
- @Override
- public void unregisterListener(VrStateListener listener) {
- VrManagerService.this.removeListener(listener);
- }
-
- @Override
public int hasVrPackage(ComponentName packageName, int userId) {
return VrManagerService.this.hasVrPackage(packageName, userId);
}
@@ -173,6 +228,7 @@
}
publishLocalService(VrManagerInternal.class, new LocalService());
+ publishBinderService(VR_MANAGER_BINDER_SERVICE, mVrManager.asBinder());
}
@Override
@@ -551,9 +607,8 @@
* Note: Must be called while holding {@code mLock}.
*/
private void onVrModeChangedLocked() {
- for (VrStateListener l : mListeners) {
- l.onVrStateChanged(mVrModeEnabled);
- }
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_VR_STATE_CHANGE,
+ (mVrModeEnabled) ? 1 : 0, 0));
}
/**
@@ -577,9 +632,9 @@
}
}
- private boolean getVrMode() {
+ private int hasVrPackage(@NonNull ComponentName targetPackageName, int userId) {
synchronized (mLock) {
- return mVrModeEnabled;
+ return mComponentObserver.isValid(targetPackageName, userId);
}
}
@@ -593,21 +648,21 @@
}
}
- private void addListener(VrStateListener listener) {
- synchronized (mLock) {
- mListeners.add(listener);
- }
+ /*
+ * Implementation of IVrManager calls.
+ */
+
+ private void addStateCallback(IVrStateCallbacks cb) {
+ mRemoteCallbacks.register(cb);
}
- private void removeListener(VrStateListener listener) {
- synchronized (mLock) {
- mListeners.remove(listener);
- }
+ private void removeStateCallback(IVrStateCallbacks cb) {
+ mRemoteCallbacks.unregister(cb);
}
- private int hasVrPackage(@NonNull ComponentName targetPackageName, int userId) {
+ private boolean getVrMode() {
synchronized (mLock) {
- return mComponentObserver.isValid(targetPackageName, userId);
+ return mVrModeEnabled;
}
}
}
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index 6052a6e..d82b8b4 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -110,9 +110,7 @@
Log.e(TAG, "Found an element that is not a webview provider");
}
}
- } catch(XmlPullParserException e) {
- throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
- } catch(IOException e) {
+ } catch (XmlPullParserException | IOException e) {
throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
} finally {
if (parser != null) parser.close();
@@ -120,6 +118,11 @@
return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
}
+ public int getFactoryPackageVersion(String packageName) throws NameNotFoundException {
+ PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
+ return pm.getPackageInfo(packageName, PackageManager.MATCH_FACTORY_ONLY).versionCode;
+ }
+
/**
* Reads all signatures at the current depth (within the current provider) from the XML parser.
*/
diff --git a/services/core/java/com/android/server/webkit/SystemInterface.java b/services/core/java/com/android/server/webkit/SystemInterface.java
index b5eb0a7..7bde37a 100644
--- a/services/core/java/com/android/server/webkit/SystemInterface.java
+++ b/services/core/java/com/android/server/webkit/SystemInterface.java
@@ -32,6 +32,7 @@
public interface SystemInterface {
public WebViewProviderInfo[] getWebViewPackages();
public int onWebViewProviderChanged(PackageInfo packageInfo);
+ public int getFactoryPackageVersion(String packageName) throws NameNotFoundException;
public String getUserChosenWebViewProvider(Context context);
public void updateUserSetting(Context context, String newProviderName);
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 4669676..17efcc2 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -61,6 +62,8 @@
private int NUMBER_OF_RELROS_UNKNOWN = Integer.MAX_VALUE;
+ private int mMinimumVersionCode = -1;
+
// The WebView package currently in use (or the one we are preparing).
private PackageInfo mCurrentWebViewPackage = null;
@@ -435,12 +438,46 @@
/**
+ * Gets the minimum version code allowed for a valid provider. It is the minimum versionCode of
+ * all available-by-default and non-fallback WebView provider packages. If there is no such
+ * WebView provider package on the system, then return -1, which means all positive versionCode
+ * WebView packages are accepted.
+ */
+ private int getMinimumVersionCode() {
+ if (mMinimumVersionCode > 0) {
+ return mMinimumVersionCode;
+ }
+
+ for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
+ if (provider.availableByDefault && !provider.isFallback) {
+ try {
+ int versionCode = mSystemInterface.getFactoryPackageVersion(provider.packageName);
+ if (mMinimumVersionCode < 0 || versionCode < mMinimumVersionCode) {
+ mMinimumVersionCode = versionCode;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // Safe to ignore.
+ }
+ }
+ }
+
+ return mMinimumVersionCode;
+ }
+
+ /**
* Returns whether this provider is valid for use as a WebView provider.
*/
- public boolean isValidProvider(WebViewProviderInfo configInfo,
+ private boolean isValidProvider(WebViewProviderInfo configInfo,
PackageInfo packageInfo) {
- if (providerHasValidSignature(configInfo, packageInfo) &&
- WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo) != null) {
+ if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0
+ && packageInfo.versionCode < getMinimumVersionCode()
+ && !mSystemInterface.systemIsDebuggable()) {
+ // Non-system package webview providers may be downgraded arbitrarily low, prevent that
+ // by enforcing minimum version code. This check is only enforced for user builds.
+ return false;
+ }
+ if (providerHasValidSignature(configInfo, packageInfo)
+ && WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo) != null) {
return true;
}
return false;
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index d684278..11b01cc 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -881,7 +881,7 @@
* when a thumbnail is specified with the pending animation override.
*/
Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets,
- Bitmap thumbnailHeader, final int taskId, int orientation) {
+ Bitmap thumbnailHeader, final int taskId, int uiMode, int orientation) {
Animation a;
final int thumbWidthI = thumbnailHeader.getWidth();
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
@@ -896,7 +896,7 @@
final float toY;
final float pivotX;
final float pivotY;
- if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ if (isTvUiMode(uiMode) || orientation == Configuration.ORIENTATION_PORTRAIT) {
fromX = mTmpRect.left;
fromY = mTmpRect.top;
@@ -1028,7 +1028,7 @@
* activity that is leaving, and the activity that is entering.
*/
Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
- int orientation, int transit, Rect containingFrame, Rect contentInsets,
+ int uiMode, int orientation, int transit, Rect containingFrame, Rect contentInsets,
@Nullable Rect surfaceInsets, boolean freeform, int taskId) {
Animation a;
final int appWidth = containingFrame.width();
@@ -1067,8 +1067,7 @@
mTmpFromClipRect.inset(contentInsets);
mNextAppTransitionInsets.set(contentInsets);
- if (orientation == Configuration.ORIENTATION_PORTRAIT) {
- // We scale the width and clip to the top/left square
+ if (isTvUiMode(uiMode) || orientation == Configuration.ORIENTATION_PORTRAIT) {
// We scale the width and clip to the top/left square
float scale = thumbWidth /
(appWidth - contentInsets.left - contentInsets.right);
@@ -1401,7 +1400,7 @@
* to the recents thumbnail and hence need to account for the surface being
* bigger.
*/
- Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
+ Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, int uiMode,
int orientation, Rect frame, Rect displayFrame, Rect insets,
@Nullable Rect surfaceInsets, boolean isVoiceInteraction, boolean freeform,
int taskId) {
@@ -1481,7 +1480,7 @@
mNextAppTransitionScaleUp =
(mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
a = createAspectScaledThumbnailEnterExitAnimationLocked(
- getThumbnailTransitionState(enter), orientation, transit, frame,
+ getThumbnailTransitionState(enter), uiMode, orientation, transit, frame,
insets, surfaceInsets, freeform, taskId);
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
String animName = mNextAppTransitionScaleUp ?
@@ -1922,4 +1921,11 @@
}
return prepared;
}
+
+ /**
+ * @return whether the specified {@param uiMode} is the TV mode.
+ */
+ private boolean isTvUiMode(int uiMode) {
+ return (uiMode & Configuration.UI_MODE_TYPE_TELEVISION) > 0;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5de2182..664a58b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3058,7 +3058,7 @@
if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "Loading animation for app transition."
+ " transit=" + AppTransition.appTransitionToString(transit) + " enter=" + enter
+ " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets);
- Animation a = mAppTransition.loadAnimation(lp, transit, enter,
+ Animation a = mAppTransition.loadAnimation(lp, transit, enter, mCurConfiguration.uiMode,
mCurConfiguration.orientation, frame, displayFrame, insets, surfaceInsets,
isVoiceInteraction, freeform, atoken.mTask.mTaskId);
if (a != null) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index eda2f39..04aa735 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -1582,7 +1582,8 @@
// synchronize its thumbnail surface with the surface for the
// open/close animation (only on the way down)
anim = mService.mAppTransition.createThumbnailAspectScaleAnimationLocked(appRect,
- insets, thumbnailHeader, taskId, mService.mCurConfiguration.orientation);
+ insets, thumbnailHeader, taskId, mService.mCurConfiguration.uiMode,
+ mService.mCurConfiguration.orientation);
openingAppAnimator.thumbnailForceAboveLayer = Math.max(openingLayer, closingLayer);
openingAppAnimator.deferThumbnailDestruction =
!mService.mAppTransition.isNextThumbnailTransitionScaleUp();
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index 876a422..ef11d66 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -66,6 +66,7 @@
ResourceValues.cpp \
SdkConstants.cpp \
StringPool.cpp \
+ xml/XmlActionExecutor.cpp \
xml/XmlDom.cpp \
xml/XmlPullParser.cpp \
xml/XmlUtil.cpp
@@ -107,6 +108,7 @@
SdkConstants_test.cpp \
StringPool_test.cpp \
ValueVisitor_test.cpp \
+ xml/XmlActionExecutor_test.cpp \
xml/XmlDom_test.cpp \
xml/XmlPullParser_test.cpp \
xml/XmlUtil_test.cpp
@@ -140,7 +142,7 @@
endif
cFlags := -Wall -Werror -Wno-unused-parameter -UNDEBUG
-cppFlags := -std=c++11 -Wno-missing-field-initializers -fno-exceptions -fno-rtti
+cppFlags := -std=c++14 -Wno-missing-field-initializers -fno-exceptions -fno-rtti
protoIncludes := $(call generated-sources-dir-for,STATIC_LIBRARIES,libaapt2,HOST)
# ==========================================================
diff --git a/tools/aapt2/Diagnostics.h b/tools/aapt2/Diagnostics.h
index ab4d284..e86f2a8 100644
--- a/tools/aapt2/Diagnostics.h
+++ b/tools/aapt2/Diagnostics.h
@@ -21,6 +21,7 @@
#include "util/StringPiece.h"
#include "util/Util.h"
+#include <android-base/macros.h>
#include <iostream>
#include <sstream>
#include <string>
@@ -46,7 +47,11 @@
DiagMessage(const Source& src) : mSource(src) {
}
- template <typename T> DiagMessage& operator<<(const T& value) {
+ DiagMessage(size_t line) : mSource(Source().withLine(line)) {
+ }
+
+ template <typename T>
+ DiagMessage& operator<<(const T& value) {
mMessage << value;
return *this;
}
@@ -59,36 +64,82 @@
struct IDiagnostics {
virtual ~IDiagnostics() = default;
- virtual void error(const DiagMessage& message) = 0;
- virtual void warn(const DiagMessage& message) = 0;
- virtual void note(const DiagMessage& message) = 0;
+ enum class Level {
+ Note,
+ Warn,
+ Error
+ };
+
+ virtual void log(Level level, DiagMessageActual& actualMsg) = 0;
+
+ virtual void error(const DiagMessage& message) {
+ DiagMessageActual actual = message.build();
+ log(Level::Error, actual);
+ }
+
+ virtual void warn(const DiagMessage& message) {
+ DiagMessageActual actual = message.build();
+ log(Level::Warn, actual);
+ }
+
+ virtual void note(const DiagMessage& message) {
+ DiagMessageActual actual = message.build();
+ log(Level::Note, actual);
+ }
};
-struct StdErrDiagnostics : public IDiagnostics {
+class StdErrDiagnostics : public IDiagnostics {
+public:
+ StdErrDiagnostics() = default;
+
+ void log(Level level, DiagMessageActual& actualMsg) override {
+ const char* tag;
+
+ switch (level) {
+ case Level::Error:
+ mNumErrors++;
+ if (mNumErrors > 20) {
+ return;
+ }
+ tag = "error";
+ break;
+
+ case Level::Warn:
+ tag = "warn";
+ break;
+
+ case Level::Note:
+ tag = "note";
+ break;
+ }
+
+ if (!actualMsg.source.path.empty()) {
+ std::cerr << actualMsg.source << ": ";
+ }
+ std::cerr << tag << ": " << actualMsg.message << "." << std::endl;
+ }
+
+private:
size_t mNumErrors = 0;
- void emit(const DiagMessage& msg, const char* tag) {
- DiagMessageActual actual = msg.build();
- if (!actual.source.path.empty()) {
- std::cerr << actual.source << ": ";
- }
- std::cerr << tag << actual.message << "." << std::endl;
+ DISALLOW_COPY_AND_ASSIGN(StdErrDiagnostics);
+};
+
+class SourcePathDiagnostics : public IDiagnostics {
+public:
+ SourcePathDiagnostics(const Source& src, IDiagnostics* diag) : mSource(src), mDiag(diag) {
}
- void error(const DiagMessage& msg) override {
- if (mNumErrors < 20) {
- emit(msg, "error: ");
- }
- mNumErrors++;
+ void log(Level level, DiagMessageActual& actualMsg) override {
+ actualMsg.source.path = mSource.path;
+ mDiag->log(level, actualMsg);
}
- void warn(const DiagMessage& msg) override {
- emit(msg, "warn: ");
- }
+private:
+ Source mSource;
+ IDiagnostics* mDiag;
- void note(const DiagMessage& msg) override {
- emit(msg, "note: ");
- }
+ DISALLOW_COPY_AND_ASSIGN(SourcePathDiagnostics);
};
} // namespace aapt
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index 180bd11..d6c52ab 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -28,33 +28,23 @@
namespace aapt {
-struct ResourceTableTest : public ::testing::Test {
- struct EmptyDiagnostics : public IDiagnostics {
- void error(const DiagMessage& msg) override {}
- void warn(const DiagMessage& msg) override {}
- void note(const DiagMessage& msg) override {}
- };
-
- EmptyDiagnostics mDiagnostics;
-};
-
-TEST_F(ResourceTableTest, FailToAddResourceWithBadName) {
+TEST(ResourceTableTest, FailToAddResourceWithBadName) {
ResourceTable table;
EXPECT_FALSE(table.addResource(
ResourceNameRef(u"android", ResourceType::kId, u"hey,there"),
ConfigDescription{}, "",
test::ValueBuilder<Id>().setSource("test.xml", 21u).build(),
- &mDiagnostics));
+ test::getDiagnostics()));
EXPECT_FALSE(table.addResource(
ResourceNameRef(u"android", ResourceType::kId, u"hey:there"),
ConfigDescription{}, "",
test::ValueBuilder<Id>().setSource("test.xml", 21u).build(),
- &mDiagnostics));
+ test::getDiagnostics()));
}
-TEST_F(ResourceTableTest, AddOneResource) {
+TEST(ResourceTableTest, AddOneResource) {
ResourceTable table;
EXPECT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/id"),
@@ -62,12 +52,12 @@
"",
test::ValueBuilder<Id>()
.setSource("test/path/file.xml", 23u).build(),
- &mDiagnostics));
+ test::getDiagnostics()));
ASSERT_NE(nullptr, test::getValue<Id>(&table, u"@android:attr/id"));
}
-TEST_F(ResourceTableTest, AddMultipleResources) {
+TEST(ResourceTableTest, AddMultipleResources) {
ResourceTable table;
ConfigDescription config;
@@ -79,21 +69,21 @@
config,
"",
test::ValueBuilder<Id>().setSource("test/path/file.xml", 10u).build(),
- &mDiagnostics));
+ test::getDiagnostics()));
EXPECT_TRUE(table.addResource(
test::parseNameOrDie(u"@android:attr/id"),
config,
"",
test::ValueBuilder<Id>().setSource("test/path/file.xml", 12u).build(),
- &mDiagnostics));
+ test::getDiagnostics()));
EXPECT_TRUE(table.addResource(
test::parseNameOrDie(u"@android:string/ok"),
config,
"",
test::ValueBuilder<Id>().setSource("test/path/file.xml", 14u).build(),
- &mDiagnostics));
+ test::getDiagnostics()));
EXPECT_TRUE(table.addResource(
test::parseNameOrDie(u"@android:string/ok"),
@@ -102,7 +92,7 @@
test::ValueBuilder<BinaryPrimitive>(android::Res_value{})
.setSource("test/path/file.xml", 20u)
.build(),
- &mDiagnostics));
+ test::getDiagnostics()));
ASSERT_NE(nullptr, test::getValue<Id>(&table, u"@android:attr/layout_width"));
ASSERT_NE(nullptr, test::getValue<Id>(&table, u"@android:attr/id"));
@@ -111,37 +101,37 @@
languageConfig));
}
-TEST_F(ResourceTableTest, OverrideWeakResourceValue) {
+TEST(ResourceTableTest, OverrideWeakResourceValue) {
ResourceTable table;
ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/foo"), ConfigDescription{},
- "", util::make_unique<Attribute>(true), &mDiagnostics));
+ "", util::make_unique<Attribute>(true), test::getDiagnostics()));
Attribute* attr = test::getValue<Attribute>(&table, u"@android:attr/foo");
ASSERT_NE(nullptr, attr);
EXPECT_TRUE(attr->isWeak());
ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/foo"), ConfigDescription{},
- "", util::make_unique<Attribute>(false), &mDiagnostics));
+ "", util::make_unique<Attribute>(false), test::getDiagnostics()));
attr = test::getValue<Attribute>(&table, u"@android:attr/foo");
ASSERT_NE(nullptr, attr);
EXPECT_FALSE(attr->isWeak());
}
-TEST_F(ResourceTableTest, ProductVaryingValues) {
+TEST(ResourceTableTest, ProductVaryingValues) {
ResourceTable table;
EXPECT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/foo"),
test::parseConfigOrDie("land"),
"tablet",
util::make_unique<Id>(),
- &mDiagnostics));
+ test::getDiagnostics()));
EXPECT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/foo"),
test::parseConfigOrDie("land"),
"phone",
util::make_unique<Id>(),
- &mDiagnostics));
+ test::getDiagnostics()));
EXPECT_NE(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/foo",
test::parseConfigOrDie("land"),
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 9baf1d8..b994664 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -17,66 +17,197 @@
#include "ResourceUtils.h"
#include "link/ManifestFixer.h"
#include "util/Util.h"
+#include "xml/XmlActionExecutor.h"
#include "xml/XmlDom.h"
namespace aapt {
-static bool verifyManifest(IAaptContext* context, const Source& source, xml::Element* manifestEl) {
- xml::Attribute* attr = manifestEl->findAttribute({}, u"package");
- if (!attr) {
- context->getDiagnostics()->error(DiagMessage(source.withLine(manifestEl->lineNumber))
- << "missing 'package' attribute");
- } else if (ResourceUtils::isReference(attr->value)) {
- context->getDiagnostics()->error(DiagMessage(source.withLine(manifestEl->lineNumber))
- << "value for attribute 'package' must not be a "
- "reference");
- } else if (!util::isJavaPackageName(attr->value)) {
- context->getDiagnostics()->error(DiagMessage(source.withLine(manifestEl->lineNumber))
- << "invalid package name '" << attr->value << "'");
- } else {
- return true;
+/**
+ * This is how PackageManager builds class names from AndroidManifest.xml entries.
+ */
+static bool nameIsJavaClassName(xml::Element* el, xml::Attribute* attr,
+ SourcePathDiagnostics* diag) {
+ std::u16string className = attr->value;
+ if (className.find(u'.') == std::u16string::npos) {
+ // There is no '.', so add one to the beginning.
+ className = u".";
+ className += attr->value;
}
+
+ // We allow unqualified class names (ie: .HelloActivity)
+ // Since we don't know the package name, we can just make a fake one here and
+ // the test will be identical as long as the real package name is valid too.
+ Maybe<std::u16string> fullyQualifiedClassName =
+ util::getFullyQualifiedClassName(u"a", className);
+
+ StringPiece16 qualifiedClassName = fullyQualifiedClassName
+ ? fullyQualifiedClassName.value() : className;
+ if (!util::isJavaClassName(qualifiedClassName)) {
+ diag->error(DiagMessage(el->lineNumber)
+ << "attribute 'android:name' in <"
+ << el->name << "> tag must be a valid Java class name");
+ return false;
+ }
+ return true;
+}
+
+static bool optionalNameIsJavaClassName(xml::Element* el, SourcePathDiagnostics* diag) {
+ if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"name")) {
+ return nameIsJavaClassName(el, attr, diag);
+ }
+ return true;
+}
+
+static bool requiredNameIsJavaClassName(xml::Element* el, SourcePathDiagnostics* diag) {
+ if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"name")) {
+ return nameIsJavaClassName(el, attr, diag);
+ }
+ diag->error(DiagMessage(el->lineNumber)
+ << "<" << el->name << "> is missing attribute 'android:name'");
return false;
}
-static bool includeVersionName(IAaptContext* context, const Source& source,
- const StringPiece16& versionName, xml::Element* manifestEl) {
- if (manifestEl->findAttribute(xml::kSchemaAndroid, u"versionName")) {
- return true;
+static bool verifyManifest(xml::Element* el, SourcePathDiagnostics* diag) {
+ xml::Attribute* attr = el->findAttribute({}, u"package");
+ if (!attr) {
+ diag->error(DiagMessage(el->lineNumber) << "<manifest> tag is missing 'package' attribute");
+ return false;
+ } else if (ResourceUtils::isReference(attr->value)) {
+ diag->error(DiagMessage(el->lineNumber)
+ << "attribute 'package' in <manifest> tag must not be a reference");
+ return false;
+ } else if (!util::isJavaPackageName(attr->value)) {
+ diag->error(DiagMessage(el->lineNumber)
+ << "attribute 'package' in <manifest> tag is not a valid Java package name: '"
+ << attr->value << "'");
+ return false;
}
-
- manifestEl->attributes.push_back(xml::Attribute{
- xml::kSchemaAndroid, u"versionName", versionName.toString() });
return true;
}
-static bool includeVersionCode(IAaptContext* context, const Source& source,
- const StringPiece16& versionCode, xml::Element* manifestEl) {
- if (manifestEl->findAttribute(xml::kSchemaAndroid, u"versionCode")) {
+bool ManifestFixer::buildRules(xml::XmlActionExecutor* executor, IDiagnostics* diag) {
+ // First verify some options.
+ if (mOptions.renameManifestPackage) {
+ if (!util::isJavaPackageName(mOptions.renameManifestPackage.value())) {
+ diag->error(DiagMessage() << "invalid manifest package override '"
+ << mOptions.renameManifestPackage.value() << "'");
+ return false;
+ }
+ }
+
+ if (mOptions.renameInstrumentationTargetPackage) {
+ if (!util::isJavaPackageName(mOptions.renameInstrumentationTargetPackage.value())) {
+ diag->error(DiagMessage() << "invalid instrumentation target package override '"
+ << mOptions.renameInstrumentationTargetPackage.value() << "'");
+ return false;
+ }
+ }
+
+ // Common intent-filter actions.
+ xml::XmlNodeAction intentFilterAction;
+ intentFilterAction[u"action"];
+ intentFilterAction[u"category"];
+ intentFilterAction[u"data"];
+
+ // Common meta-data actions.
+ xml::XmlNodeAction metaDataAction;
+
+ // Manifest actions.
+ xml::XmlNodeAction& manifestAction = (*executor)[u"manifest"];
+ manifestAction.action(verifyManifest);
+ manifestAction.action([&](xml::Element* el) -> bool {
+ if (mOptions.versionNameDefault) {
+ if (el->findAttribute(xml::kSchemaAndroid, u"versionName") == nullptr) {
+ el->attributes.push_back(xml::Attribute{
+ xml::kSchemaAndroid,
+ u"versionName",
+ mOptions.versionNameDefault.value() });
+ }
+ }
+
+ if (mOptions.versionCodeDefault) {
+ if (el->findAttribute(xml::kSchemaAndroid, u"versionCode") == nullptr) {
+ el->attributes.push_back(xml::Attribute{
+ xml::kSchemaAndroid,
+ u"versionCode",
+ mOptions.versionCodeDefault.value() });
+ }
+ }
return true;
- }
+ });
- manifestEl->attributes.push_back(xml::Attribute{
- xml::kSchemaAndroid, u"versionCode", versionCode.toString() });
- return true;
-}
+ // Uses-sdk actions.
+ manifestAction[u"uses-sdk"].action([&](xml::Element* el) -> bool {
+ if (mOptions.minSdkVersionDefault &&
+ el->findAttribute(xml::kSchemaAndroid, u"minSdkVersion") == nullptr) {
+ // There was no minSdkVersion defined and we have a default to assign.
+ el->attributes.push_back(xml::Attribute{
+ xml::kSchemaAndroid, u"minSdkVersion",
+ mOptions.minSdkVersionDefault.value() });
+ }
-static bool fixUsesSdk(IAaptContext* context, const Source& source, xml::Element* el,
- const ManifestFixerOptions& options) {
- if (options.minSdkVersionDefault &&
- el->findAttribute(xml::kSchemaAndroid, u"minSdkVersion") == nullptr) {
- // There was no minSdkVersion defined and we have a default to assign.
- el->attributes.push_back(xml::Attribute{
- xml::kSchemaAndroid, u"minSdkVersion", options.minSdkVersionDefault.value() });
- }
+ if (mOptions.targetSdkVersionDefault &&
+ el->findAttribute(xml::kSchemaAndroid, u"targetSdkVersion") == nullptr) {
+ // There was no targetSdkVersion defined and we have a default to assign.
+ el->attributes.push_back(xml::Attribute{
+ xml::kSchemaAndroid, u"targetSdkVersion",
+ mOptions.targetSdkVersionDefault.value() });
+ }
+ return true;
+ });
- if (options.targetSdkVersionDefault &&
- el->findAttribute(xml::kSchemaAndroid, u"targetSdkVersion") == nullptr) {
- // There was no targetSdkVersion defined and we have a default to assign.
- el->attributes.push_back(xml::Attribute{
- xml::kSchemaAndroid, u"targetSdkVersion",
- options.targetSdkVersionDefault.value() });
- }
+ // Instrumentation actions.
+ manifestAction[u"instrumentation"].action([&](xml::Element* el) -> bool {
+ if (!mOptions.renameInstrumentationTargetPackage) {
+ return true;
+ }
+
+ if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"targetPackage")) {
+ attr->value = mOptions.renameInstrumentationTargetPackage.value();
+ }
+ return true;
+ });
+
+ manifestAction[u"uses-permission"];
+ manifestAction[u"permission"];
+ manifestAction[u"permission-tree"];
+ manifestAction[u"permission-group"];
+
+ manifestAction[u"uses-configuration"];
+ manifestAction[u"uses-feature"];
+ manifestAction[u"uses-library"];
+ manifestAction[u"supports-screens"];
+ manifestAction[u"compatible-screens"];
+ manifestAction[u"supports-gl-texture"];
+
+ // Application actions.
+ xml::XmlNodeAction& applicationAction = (*executor)[u"manifest"][u"application"];
+ applicationAction.action(optionalNameIsJavaClassName);
+
+ // Activity actions.
+ applicationAction[u"activity"].action(requiredNameIsJavaClassName);
+ applicationAction[u"activity"][u"intent-filter"] = intentFilterAction;
+ applicationAction[u"activity"][u"meta-data"] = metaDataAction;
+
+ // Activity alias actions.
+ applicationAction[u"activity-alias"][u"intent-filter"] = intentFilterAction;
+ applicationAction[u"activity-alias"][u"meta-data"] = metaDataAction;
+
+ // Service actions.
+ applicationAction[u"service"].action(requiredNameIsJavaClassName);
+ applicationAction[u"service"][u"intent-filter"] = intentFilterAction;
+ applicationAction[u"service"][u"meta-data"] = metaDataAction;
+
+ // Receiver actions.
+ applicationAction[u"receiver"].action(requiredNameIsJavaClassName);
+ applicationAction[u"receiver"][u"intent-filter"] = intentFilterAction;
+ applicationAction[u"receiver"][u"meta-data"] = metaDataAction;
+
+ // Provider actions.
+ applicationAction[u"provider"].action(requiredNameIsJavaClassName);
+ applicationAction[u"provider"][u"grant-uri-permissions"];
+ applicationAction[u"provider"][u"meta-data"] = metaDataAction;
+ applicationAction[u"provider"][u"path-permissions"];
return true;
}
@@ -103,14 +234,7 @@
StringPiece16 mPackage;
};
-static bool renameManifestPackage(IAaptContext* context, const Source& source,
- const StringPiece16& packageOverride, xml::Element* manifestEl) {
- if (!util::isJavaPackageName(packageOverride)) {
- context->getDiagnostics()->error(DiagMessage() << "invalid manifest package override '"
- << packageOverride << "'");
- return false;
- }
-
+static bool renameManifestPackage(const StringPiece16& packageOverride, xml::Element* manifestEl) {
xml::Attribute* attr = manifestEl->findAttribute({}, u"package");
// We've already verified that the manifest element is present, with a package name specified.
@@ -124,32 +248,6 @@
return true;
}
-static bool renameInstrumentationTargetPackage(IAaptContext* context, const Source& source,
- const StringPiece16& packageOverride,
- xml::Element* manifestEl) {
- if (!util::isJavaPackageName(packageOverride)) {
- context->getDiagnostics()->error(DiagMessage()
- << "invalid instrumentation target package override '"
- << packageOverride << "'");
- return false;
- }
-
- xml::Element* instrumentationEl = manifestEl->findChild({}, u"instrumentation");
- if (!instrumentationEl) {
- // No error if there is no work to be done.
- return true;
- }
-
- xml::Attribute* attr = instrumentationEl->findAttribute(xml::kSchemaAndroid, u"targetPackage");
- if (!attr) {
- // No error if there is no work to be done.
- return true;
- }
-
- attr->value = packageOverride.toString();
- return true;
-}
-
bool ManifestFixer::consume(IAaptContext* context, xml::XmlResource* doc) {
xml::Element* root = xml::findRootElement(doc->root.get());
if (!root || !root->namespaceUri.empty() || root->name != u"manifest") {
@@ -158,59 +256,31 @@
return false;
}
- if (!verifyManifest(context, doc->file.source, root)) {
- return false;
- }
-
- if (mOptions.versionCodeDefault) {
- if (!includeVersionCode(context, doc->file.source, mOptions.versionCodeDefault.value(),
- root)) {
- return false;
- }
- }
-
- if (mOptions.versionNameDefault) {
- if (!includeVersionName(context, doc->file.source, mOptions.versionNameDefault.value(),
- root)) {
- return false;
- }
- }
-
- if (mOptions.renameManifestPackage) {
- // Rename manifest package.
- if (!renameManifestPackage(context, doc->file.source,
- mOptions.renameManifestPackage.value(), root)) {
- return false;
- }
- }
-
- if (mOptions.renameInstrumentationTargetPackage) {
- if (!renameInstrumentationTargetPackage(context, doc->file.source,
- mOptions.renameInstrumentationTargetPackage.value(),
- root)) {
- return false;
- }
- }
-
- bool foundUsesSdk = false;
- for (xml::Element* el : root->getChildElements()) {
- if (!el->namespaceUri.empty()) {
- continue;
- }
-
- if (el->name == u"uses-sdk") {
- foundUsesSdk = true;
- fixUsesSdk(context, doc->file.source, el, mOptions);
- }
- }
-
- if (!foundUsesSdk && (mOptions.minSdkVersionDefault || mOptions.targetSdkVersionDefault)) {
+ if ((mOptions.minSdkVersionDefault || mOptions.targetSdkVersionDefault)
+ && root->findChild({}, u"uses-sdk") == nullptr) {
+ // Auto insert a <uses-sdk> element.
std::unique_ptr<xml::Element> usesSdk = util::make_unique<xml::Element>();
usesSdk->name = u"uses-sdk";
- fixUsesSdk(context, doc->file.source, usesSdk.get(), mOptions);
root->addChild(std::move(usesSdk));
}
+ xml::XmlActionExecutor executor;
+ if (!buildRules(&executor, context->getDiagnostics())) {
+ return false;
+ }
+
+ if (!executor.execute(xml::XmlActionExecutorPolicy::Whitelist, context->getDiagnostics(),
+ doc)) {
+ return false;
+ }
+
+ if (mOptions.renameManifestPackage) {
+ // Rename manifest package outside of the XmlActionExecutor.
+ // We need to extract the old package name and FullyQualify all class names.
+ if (!renameManifestPackage(mOptions.renameManifestPackage.value(), root)) {
+ return false;
+ }
+ }
return true;
}
diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h
index b8d9c83..4d9356a 100644
--- a/tools/aapt2/link/ManifestFixer.h
+++ b/tools/aapt2/link/ManifestFixer.h
@@ -19,6 +19,7 @@
#include "process/IResourceTableConsumer.h"
#include "util/Maybe.h"
+#include "xml/XmlActionExecutor.h"
#include "xml/XmlDom.h"
#include <string>
@@ -38,13 +39,17 @@
* Verifies that the manifest is correctly formed and inserts defaults
* where specified with ManifestFixerOptions.
*/
-struct ManifestFixer : public IXmlResourceConsumer {
- ManifestFixerOptions mOptions;
-
+class ManifestFixer : public IXmlResourceConsumer {
+public:
ManifestFixer(const ManifestFixerOptions& options) : mOptions(options) {
}
bool consume(IAaptContext* context, xml::XmlResource* doc) override;
+
+private:
+ bool buildRules(xml::XmlActionExecutor* executor, IDiagnostics* diag);
+
+ ManifestFixerOptions mOptions;
};
} // namespace aapt
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index 18c47df..f993720 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -166,9 +166,9 @@
std::unique_ptr<xml::XmlResource> doc = verifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android">
- <application name=".MainApplication" text="hello">
- <activity name=".activity.Start" />
- <receiver name="com.google.android.Receiver" />
+ <application android:name=".MainApplication" text="hello">
+ <activity android:name=".activity.Start" />
+ <receiver android:name="com.google.android.Receiver" />
</application>
</manifest>)EOF", options);
ASSERT_NE(nullptr, doc);
@@ -185,7 +185,7 @@
xml::Element* applicationEl = manifestEl->findChild({}, u"application");
ASSERT_NE(nullptr, applicationEl);
- attr = applicationEl->findAttribute({}, u"name");
+ attr = applicationEl->findAttribute(xml::kSchemaAndroid, u"name");
ASSERT_NE(nullptr, attr);
EXPECT_EQ(std::u16string(u"android.MainApplication"), attr->value);
@@ -197,14 +197,14 @@
el = applicationEl->findChild({}, u"activity");
ASSERT_NE(nullptr, el);
- attr = el->findAttribute({}, u"name");
+ attr = el->findAttribute(xml::kSchemaAndroid, u"name");
ASSERT_NE(nullptr, el);
EXPECT_EQ(std::u16string(u"android.activity.Start"), attr->value);
el = applicationEl->findChild({}, u"receiver");
ASSERT_NE(nullptr, el);
- attr = el->findAttribute({}, u"name");
+ attr = el->findAttribute(xml::kSchemaAndroid, u"name");
ASSERT_NE(nullptr, el);
EXPECT_EQ(std::u16string(u"com.google.android.Receiver"), attr->value);
}
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 8c56ebc..8eb4bc8 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -238,7 +238,7 @@
std::stringstream in;
in << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" << str;
StdErrDiagnostics diag;
- std::unique_ptr<xml::XmlResource> doc = xml::inflate(&in, &diag, {});
+ std::unique_ptr<xml::XmlResource> doc = xml::inflate(&in, &diag, Source("test.xml"));
assert(doc);
return doc;
}
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index 348c32a..faccd477 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -41,15 +41,20 @@
namespace test {
struct DummyDiagnosticsImpl : public IDiagnostics {
- void error(const DiagMessage& message) override {
- DiagMessageActual actual = message.build();
- std::cerr << actual.source << ": error: " << actual.message << "." << std::endl;
+ void log(Level level, DiagMessageActual& actualMsg) override {
+ switch (level) {
+ case Level::Note:
+ return;
+
+ case Level::Warn:
+ std::cerr << actualMsg.source << ": warn: " << actualMsg.message << "." << std::endl;
+ break;
+
+ case Level::Error:
+ std::cerr << actualMsg.source << ": error: " << actualMsg.message << "." << std::endl;
+ break;
+ }
}
- void warn(const DiagMessage& message) override {
- DiagMessageActual actual = message.build();
- std::cerr << actual.source << ": warn: " << actual.message << "." << std::endl;
- }
- void note(const DiagMessage& message) override {}
};
inline IDiagnostics* getDiagnostics() {
diff --git a/tools/aapt2/xml/XmlActionExecutor.cpp b/tools/aapt2/xml/XmlActionExecutor.cpp
new file mode 100644
index 0000000..0ef67ea
--- /dev/null
+++ b/tools/aapt2/xml/XmlActionExecutor.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "xml/XmlActionExecutor.h"
+
+namespace aapt {
+namespace xml {
+
+static bool wrapperOne(XmlNodeAction::ActionFunc& f, Element* el, SourcePathDiagnostics*) {
+ return f(el);
+}
+
+static bool wrapperTwo(XmlNodeAction::ActionFuncWithDiag& f, Element* el,
+ SourcePathDiagnostics* diag) {
+ return f(el, diag);
+}
+
+void XmlNodeAction::action(XmlNodeAction::ActionFunc f) {
+ mActions.emplace_back(std::bind(wrapperOne, std::move(f),
+ std::placeholders::_1,
+ std::placeholders::_2));
+}
+
+void XmlNodeAction::action(XmlNodeAction::ActionFuncWithDiag f) {
+ mActions.emplace_back(std::bind(wrapperTwo, std::move(f),
+ std::placeholders::_1,
+ std::placeholders::_2));
+}
+
+static void printElementToDiagMessage(const Element* el, DiagMessage* msg) {
+ *msg << "<";
+ if (!el->namespaceUri.empty()) {
+ *msg << el->namespaceUri << ":";
+ }
+ *msg << el->name << ">";
+}
+
+bool XmlNodeAction::execute(XmlActionExecutorPolicy policy, SourcePathDiagnostics* diag,
+ Element* el) const {
+ bool error = false;
+ for (const ActionFuncWithDiag& action : mActions) {
+ error |= !action(el, diag);
+ }
+
+ for (Element* childEl : el->getChildElements()) {
+ if (childEl->namespaceUri.empty()) {
+ std::map<std::u16string, XmlNodeAction>::const_iterator iter =
+ mMap.find(childEl->name);
+ if (iter != mMap.end()) {
+ error |= !iter->second.execute(policy, diag, childEl);
+ continue;
+ }
+ }
+
+ if (policy == XmlActionExecutorPolicy::Whitelist) {
+ DiagMessage errorMsg(childEl->lineNumber);
+ errorMsg << "unknown element ";
+ printElementToDiagMessage(childEl, &errorMsg);
+ errorMsg << " found";
+ diag->error(errorMsg);
+ error = true;
+ }
+ }
+ return !error;
+}
+
+bool XmlActionExecutor::execute(XmlActionExecutorPolicy policy, IDiagnostics* diag,
+ XmlResource* doc) const {
+ SourcePathDiagnostics sourceDiag(doc->file.source, diag);
+
+ Element* el = findRootElement(doc);
+ if (!el) {
+ if (policy == XmlActionExecutorPolicy::Whitelist) {
+ sourceDiag.error(DiagMessage() << "no root XML tag found");
+ return false;
+ }
+ return true;
+ }
+
+ if (el->namespaceUri.empty()) {
+ std::map<std::u16string, XmlNodeAction>::const_iterator iter = mMap.find(el->name);
+ if (iter != mMap.end()) {
+ return iter->second.execute(policy, &sourceDiag, el);
+ }
+ }
+
+ if (policy == XmlActionExecutorPolicy::Whitelist) {
+ DiagMessage errorMsg(el->lineNumber);
+ errorMsg << "unknown element ";
+ printElementToDiagMessage(el, &errorMsg);
+ errorMsg << " found";
+ sourceDiag.error(errorMsg);
+ return false;
+ }
+ return true;
+}
+
+} // namespace xml
+} // namespace aapt
diff --git a/tools/aapt2/xml/XmlActionExecutor.h b/tools/aapt2/xml/XmlActionExecutor.h
new file mode 100644
index 0000000..36b94db
--- /dev/null
+++ b/tools/aapt2/xml/XmlActionExecutor.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_XML_XMLPATTERN_H
+#define AAPT_XML_XMLPATTERN_H
+
+#include "Diagnostics.h"
+#include "xml/XmlDom.h"
+
+#include <android-base/macros.h>
+#include <functional>
+#include <map>
+#include <string>
+#include <vector>
+
+namespace aapt {
+namespace xml {
+
+enum class XmlActionExecutorPolicy {
+ /**
+ * Actions on run if elements are matched, errors occur only when actions return false.
+ */
+ None,
+
+ /**
+ * The actions defined must match and run. If an element is found that does not match
+ * an action, an error occurs.
+ */
+ Whitelist,
+};
+
+/**
+ * Contains the actions to perform at this XML node. This is a recursive data structure that
+ * holds XmlNodeActions for child XML nodes.
+ */
+class XmlNodeAction {
+public:
+ using ActionFuncWithDiag = std::function<bool(Element*, SourcePathDiagnostics*)>;
+ using ActionFunc = std::function<bool(Element*)>;
+
+ /**
+ * Find or create a child XmlNodeAction that will be performed for the child element
+ * with the name `name`.
+ */
+ XmlNodeAction& operator[](const std::u16string& name) {
+ return mMap[name];
+ }
+
+ /**
+ * Add an action to be performed at this XmlNodeAction.
+ */
+ void action(ActionFunc f);
+ void action(ActionFuncWithDiag);
+
+private:
+ friend class XmlActionExecutor;
+
+ bool execute(XmlActionExecutorPolicy policy, SourcePathDiagnostics* diag, Element* el) const;
+
+ std::map<std::u16string, XmlNodeAction> mMap;
+ std::vector<ActionFuncWithDiag> mActions;
+};
+
+/**
+ * Allows the definition of actions to execute at specific XML elements defined by their
+ * hierarchy.
+ */
+class XmlActionExecutor {
+public:
+ XmlActionExecutor() = default;
+
+ /**
+ * Find or create a root XmlNodeAction that will be performed for the root XML element
+ * with the name `name`.
+ */
+ XmlNodeAction& operator[](const std::u16string& name) {
+ return mMap[name];
+ }
+
+ /**
+ * Execute the defined actions for this XmlResource.
+ * Returns true if all actions return true, otherwise returns false.
+ */
+ bool execute(XmlActionExecutorPolicy policy, IDiagnostics* diag, XmlResource* doc) const;
+
+private:
+ std::map<std::u16string, XmlNodeAction> mMap;
+
+ DISALLOW_COPY_AND_ASSIGN(XmlActionExecutor);
+};
+
+} // namespace xml
+} // namespace aapt
+
+#endif /* AAPT_XML_XMLPATTERN_H */
diff --git a/tools/aapt2/xml/XmlActionExecutor_test.cpp b/tools/aapt2/xml/XmlActionExecutor_test.cpp
new file mode 100644
index 0000000..ebf287a
--- /dev/null
+++ b/tools/aapt2/xml/XmlActionExecutor_test.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "test/Test.h"
+#include "xml/XmlActionExecutor.h"
+
+namespace aapt {
+namespace xml {
+
+TEST(XmlActionExecutorTest, BuildsAccessibleNestedPattern) {
+ XmlActionExecutor executor;
+ XmlNodeAction& manifestAction = executor[u"manifest"];
+ XmlNodeAction& applicationAction = manifestAction[u"application"];
+
+ Element* manifestEl = nullptr;
+ manifestAction.action([&](Element* manifest) -> bool {
+ manifestEl = manifest;
+ return true;
+ });
+
+ Element* applicationEl = nullptr;
+ applicationAction.action([&](Element* application) -> bool {
+ applicationEl = application;
+ return true;
+ });
+
+ std::unique_ptr<XmlResource> doc = test::buildXmlDom("<manifest><application /></manifest>");
+
+ StdErrDiagnostics diag;
+ ASSERT_TRUE(executor.execute(XmlActionExecutorPolicy::None, &diag, doc.get()));
+ ASSERT_NE(nullptr, manifestEl);
+ EXPECT_EQ(std::u16string(u"manifest"), manifestEl->name);
+
+ ASSERT_NE(nullptr, applicationEl);
+ EXPECT_EQ(std::u16string(u"application"), applicationEl->name);
+}
+
+TEST(XmlActionExecutorTest, FailsWhenUndefinedHierarchyExists) {
+ XmlActionExecutor executor;
+ executor[u"manifest"][u"application"];
+
+ std::unique_ptr<XmlResource> doc = test::buildXmlDom(
+ "<manifest><application /><activity /></manifest>");
+ StdErrDiagnostics diag;
+ ASSERT_FALSE(executor.execute(XmlActionExecutorPolicy::Whitelist, &diag, doc.get()));
+}
+
+} // namespace xml
+} // namespace aapt
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 1c7a308..6ca4393 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -149,9 +149,6 @@
void setAllowScansWithTraffic(int enabled);
int getAllowScansWithTraffic();
- void setHalBasedAutojoinOffload(int enabled);
- int getHalBasedAutojoinOffload();
-
boolean enableAutoJoinWhenAssociated(boolean enabled);
boolean getEnableAutoJoinWhenAssociated();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 8c1fbc3..6653a8d 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -28,7 +28,6 @@
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -43,7 +42,6 @@
import com.android.server.net.NetworkPinner;
import java.net.InetAddress;
-import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -2721,27 +2719,4 @@
throw e.rethrowFromSystemServer();
}
}
- /**
- * Set setting for enabling autojoin Offload thru Wifi HAL layer
- * @hide
- */
- public void setHalBasedAutojoinOffload(int enabled) {
- try {
- mService.setHalBasedAutojoinOffload(enabled);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Get setting for enabling autojoin Offload thru Wifi HAL layer
- * @hide
- */
- public int getHalBasedAutojoinOffload() {
- try {
- return mService.getHalBasedAutojoinOffload();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
}