Merge "Remove StructGroupSourceReq" into oc-mr1-dev-plus-aosp
diff --git a/config/compiled-classes-phone b/config/compiled-classes-phone
index e2b4edf..df68f14 100644
--- a/config/compiled-classes-phone
+++ b/config/compiled-classes-phone
@@ -5242,7 +5242,6 @@
com.android.internal.app.IVoiceInteractor$Stub
com.android.internal.app.NightDisplayController
com.android.internal.app.NightDisplayController$Callback
-com.android.internal.app.NightDisplayController$LocalTime
com.android.internal.app.ProcessMap
com.android.internal.app.ResolverActivity
com.android.internal.app.ToolbarActionBar
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 4f83531..0539942 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -2783,7 +2783,6 @@
com.android.internal.app.IVoiceInteractor
com.android.internal.app.IVoiceInteractor$Stub
com.android.internal.app.NightDisplayController
-com.android.internal.app.NightDisplayController$1
com.android.internal.appwidget.IAppWidgetService
com.android.internal.appwidget.IAppWidgetService$Stub
com.android.internal.appwidget.IAppWidgetService$Stub$Proxy
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index bf9bd79..a3b3a9f 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -175,6 +175,9 @@
}
if (result != null) {
response.onResult(result);
+ } else {
+ response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+ "null bundle returned");
}
} catch (Exception e) {
handleException(response, "addAccount", accountType, e);
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index dd6ad55..bd9c9fa 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -2321,6 +2321,10 @@
private class Response extends IAccountManagerResponse.Stub {
@Override
public void onResult(Bundle bundle) {
+ if (bundle == null) {
+ onError(ERROR_CODE_INVALID_RESPONSE, "null bundle returned");
+ return;
+ }
Intent intent = bundle.getParcelable(KEY_INTENT);
if (intent != null && mActivity != null) {
// since the user provided an Activity we will silently start intents
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 897e42b..1811748 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -308,7 +308,15 @@
boolean shouldUpRecreateTask(in IBinder token, in String destAffinity);
boolean navigateUpTo(in IBinder token, in Intent target, int resultCode,
in Intent resultData);
- void setLockScreenShown(boolean showing);
+ /**
+ * Informs ActivityManagerService that the keyguard is showing.
+ *
+ * @param showing True if the keyguard is showing, false otherwise.
+ * @param secondaryDisplayShowing The displayId of the secondary display on which the keyguard
+ * is showing, or INVALID_DISPLAY if there is no such display. Only meaningful if
+ * showing is true.
+ */
+ void setLockScreenShown(boolean showing, int secondaryDisplayShowing);
boolean finishActivityAffinity(in IBinder token);
// This is not public because you need to be very careful in how you
// manage your activity to make sure it is always the uid you expect.
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index ac6d83f..2623830 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -287,8 +287,10 @@
mPublisher = in.readString();
mName = in.readString();
+ mHandle = in.readInt();
mAppId = in.readLong();
mAppVersion = in.readInt();
+ mContexthubId = in.readInt();
mNeededReadMemBytes = in.readInt();
mNeededWriteMemBytes = in.readInt();
mNeededExecMemBytes = in.readInt();
@@ -309,6 +311,8 @@
public void writeToParcel(Parcel out, int flags) {
out.writeString(mPublisher);
out.writeString(mName);
+
+ out.writeInt(mHandle);
out.writeLong(mAppId);
out.writeInt(mAppVersion);
out.writeInt(mContexthubId);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 80766f0..4438edb 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6945,8 +6945,9 @@
public static final String NIGHT_DISPLAY_CUSTOM_END_TIME = "night_display_custom_end_time";
/**
- * Time in milliseconds (since epoch) when Night display was last activated. Use to decide
- * whether to apply the current activated state after a reboot or user change.
+ * A String representing the LocalDateTime when Night display was last activated. Use to
+ * decide whether to apply the current activated state after a reboot or user change. In
+ * legacy cases, this is represented by the time in milliseconds (since epoch).
* @hide
*/
public static final String NIGHT_DISPLAY_LAST_ACTIVATED_TIME =
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index cac27af..462dad3 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -231,6 +231,7 @@
updateRequestedVisibility();
mAttachedToWindow = true;
+ mParent.requestTransparentRegion(SurfaceView.this);
if (!mGlobalListenersAdded) {
ViewTreeObserver observer = getViewTreeObserver();
observer.addOnScrollChangedListener(mScrollChangedListener);
@@ -269,8 +270,6 @@
if (mPendingReportDraws > 0) {
mDrawFinished = true;
if (mAttachedToWindow) {
- mParent.requestTransparentRegion(SurfaceView.this);
-
notifyDrawFinished();
invalidate();
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 27eeb2e..f888ba2 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -37,7 +37,6 @@
import android.service.autofill.FillEventHistory;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.DebugUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
@@ -202,9 +201,12 @@
* Initial state of the autofill context, set when there is no session (i.e., when
* {@link #mSessionId} is {@link #NO_SESSION}).
*
+ * <p>In this state, app callbacks (such as {@link #notifyViewEntered(View)}) are notified to
+ * the server.
+ *
* @hide
*/
- public static final int STATE_UNKNOWN = 1;
+ public static final int STATE_UNKNOWN = 0;
/**
* State where the autofill context hasn't been {@link #commit() finished} nor
@@ -212,7 +214,18 @@
*
* @hide
*/
- public static final int STATE_ACTIVE = 2;
+ public static final int STATE_ACTIVE = 1;
+
+ /**
+ * State where the autofill context was finished by the server because the autofill
+ * service could not autofill the page.
+ *
+ * <p>In this state, most apps callback (such as {@link #notifyViewEntered(View)}) are ignored,
+ * exception {@link #requestAutofill(View)} (and {@link #requestAutofill(View, int, Rect)}).
+ *
+ * @hide
+ */
+ public static final int STATE_FINISHED = 2;
/**
* State where the autofill context has been {@link #commit() finished} but the server still has
@@ -220,7 +233,7 @@
*
* @hide
*/
- public static final int STATE_SHOWING_SAVE_UI = 4;
+ public static final int STATE_SHOWING_SAVE_UI = 3;
/**
* Makes an authentication id from a request id and a dataset id.
@@ -559,6 +572,14 @@
}
AutofillCallback callback = null;
synchronized (mLock) {
+ if (isFinishedLocked() && (flags & FLAG_MANUAL_REQUEST) == 0) {
+ if (sVerbose) {
+ Log.v(TAG, "notifyViewEntered(flags=" + flags + ", view=" + view
+ + "): ignored on state " + getStateAsStringLocked());
+ }
+ return;
+ }
+
ensureServiceClientAddedIfNeededLocked();
if (!mEnabled) {
@@ -682,6 +703,14 @@
}
AutofillCallback callback = null;
synchronized (mLock) {
+ if (isFinishedLocked() && (flags & FLAG_MANUAL_REQUEST) == 0) {
+ if (sVerbose) {
+ Log.v(TAG, "notifyViewEntered(flags=" + flags + ", view=" + view
+ + ", virtualId=" + virtualId
+ + "): ignored on state " + getStateAsStringLocked());
+ }
+ return;
+ }
ensureServiceClientAddedIfNeededLocked();
if (!mEnabled) {
@@ -765,6 +794,10 @@
}
if (!mEnabled || !isActiveLocked()) {
+ if (sVerbose && mEnabled) {
+ Log.v(TAG, "notifyValueChanged(" + view + "): ignoring on state "
+ + getStateAsStringLocked());
+ }
return;
}
@@ -950,10 +983,13 @@
@NonNull AutofillValue value, int flags) {
if (sVerbose) {
Log.v(TAG, "startSessionLocked(): id=" + id + ", bounds=" + bounds + ", value=" + value
- + ", flags=" + flags + ", state=" + mState);
+ + ", flags=" + flags + ", state=" + getStateAsStringLocked());
}
- if (mState != STATE_UNKNOWN) {
- if (sDebug) Log.d(TAG, "not starting session for " + id + " on state " + mState);
+ if (mState != STATE_UNKNOWN && (flags & FLAG_MANUAL_REQUEST) == 0) {
+ if (sVerbose) {
+ Log.v(TAG, "not automatically starting session for " + id
+ + " on state " + getStateAsStringLocked());
+ }
return;
}
try {
@@ -973,7 +1009,7 @@
}
private void finishSessionLocked() {
- if (sVerbose) Log.v(TAG, "finishSessionLocked(): " + mState);
+ if (sVerbose) Log.v(TAG, "finishSessionLocked(): " + getStateAsStringLocked());
if (!isActiveLocked()) return;
@@ -987,7 +1023,7 @@
}
private void cancelSessionLocked() {
- if (sVerbose) Log.v(TAG, "cancelSessionLocked(): " + mState);
+ if (sVerbose) Log.v(TAG, "cancelSessionLocked(): " + getStateAsStringLocked());
if (!isActiveLocked()) return;
@@ -1306,6 +1342,14 @@
}
}
+ private void setSessionFinished() {
+ if (sVerbose) Log.v(TAG, "setSessionFinished()");
+ synchronized (mLock) {
+ resetSessionLocked();
+ mState = STATE_FINISHED;
+ }
+ }
+
private void requestHideFillUi(AutofillId id) {
final View anchor = findView(id);
if (sVerbose) Log.v(TAG, "requestHideFillUi(" + id + "): anchor = " + anchor);
@@ -1341,7 +1385,11 @@
}
}
- private void notifyNoFillUi(int sessionId, AutofillId id) {
+ private void notifyNoFillUi(int sessionId, AutofillId id, boolean sessionFinished) {
+ if (sVerbose) {
+ Log.v(TAG, "notifyNoFillUi(): sessionId=" + sessionId + ", autofillId=" + id
+ + ", finished=" + sessionFinished);
+ }
final View anchor = findView(id);
if (anchor == null) {
return;
@@ -1361,7 +1409,11 @@
} else {
callback.onAutofillEvent(anchor, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
}
+ }
+ if (sessionFinished) {
+ // Callback call was "hijacked" to also update the session state.
+ setSessionFinished();
}
}
@@ -1434,8 +1486,7 @@
pw.print(outerPrefix); pw.println("AutofillManager:");
final String pfx = outerPrefix + " ";
pw.print(pfx); pw.print("sessionId: "); pw.println(mSessionId);
- pw.print(pfx); pw.print("state: "); pw.println(
- DebugUtils.flagsToString(AutofillManager.class, "STATE_", mState));
+ pw.print(pfx); pw.print("state: "); pw.println(getStateAsStringLocked());
pw.print(pfx); pw.print("enabled: "); pw.println(mEnabled);
pw.print(pfx); pw.print("hasService: "); pw.println(mService != null);
pw.print(pfx); pw.print("hasCallback: "); pw.println(mCallback != null);
@@ -1452,10 +1503,29 @@
pw.print(pfx); pw.print("fillable ids: "); pw.println(mFillableIds);
}
+ private String getStateAsStringLocked() {
+ switch (mState) {
+ case STATE_UNKNOWN:
+ return "STATE_UNKNOWN";
+ case STATE_ACTIVE:
+ return "STATE_ACTIVE";
+ case STATE_FINISHED:
+ return "STATE_FINISHED";
+ case STATE_SHOWING_SAVE_UI:
+ return "STATE_SHOWING_SAVE_UI";
+ default:
+ return "INVALID:" + mState;
+ }
+ }
+
private boolean isActiveLocked() {
return mState == STATE_ACTIVE;
}
+ private boolean isFinishedLocked() {
+ return mState == STATE_FINISHED;
+ }
+
private void post(Runnable runnable) {
final AutofillClient client = getClientLocked();
if (client == null) {
@@ -1787,10 +1857,10 @@
}
@Override
- public void notifyNoFillUi(int sessionId, AutofillId id) {
+ public void notifyNoFillUi(int sessionId, AutofillId id, boolean sessionFinished) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
- afm.post(() -> afm.notifyNoFillUi(sessionId, id));
+ afm.post(() -> afm.notifyNoFillUi(sessionId, id, sessionFinished));
}
}
@@ -1823,7 +1893,15 @@
public void setSaveUiState(int sessionId, boolean shown) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
- afm.post(() ->afm.setSaveUiState(sessionId, shown));
+ afm.post(() -> afm.setSaveUiState(sessionId, shown));
+ }
+ }
+
+ @Override
+ public void setSessionFinished() {
+ final AutofillManager afm = mAfm.get();
+ if (afm != null) {
+ afm.post(() -> afm.setSessionFinished());
}
}
}
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 0eae858..db6855a 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -67,9 +67,9 @@
void requestHideFillUi(int sessionId, in AutofillId id);
/**
- * Notifies no fill UI will be shown.
+ * Notifies no fill UI will be shown, and also mark the state as finished if necessary.
*/
- void notifyNoFillUi(int sessionId, in AutofillId id);
+ void notifyNoFillUi(int sessionId, in AutofillId id, boolean sessionFinished);
/**
* Starts the provided intent sender.
@@ -80,4 +80,10 @@
* Sets the state of the Autofill Save UI for a given session.
*/
void setSaveUiState(int sessionId, boolean shown);
+
+ /**
+ * Marks the state of the session as finished (because the AutofillService returned a null
+ * FillResponse).
+ */
+ void setSessionFinished();
}
diff --git a/core/java/com/android/internal/app/NightDisplayController.java b/core/java/com/android/internal/app/NightDisplayController.java
index 860c5c4..7a1383c 100644
--- a/core/java/com/android/internal/app/NightDisplayController.java
+++ b/core/java/com/android/internal/app/NightDisplayController.java
@@ -32,8 +32,12 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.Calendar;
-import java.util.Locale;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeParseException;
/**
* Controller for managing Night display settings.
@@ -116,8 +120,9 @@
*/
public boolean setActivated(boolean activated) {
if (isActivated() != activated) {
- Secure.putLongForUser(mContext.getContentResolver(),
- Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, System.currentTimeMillis(),
+ Secure.putStringForUser(mContext.getContentResolver(),
+ Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+ LocalDateTime.now().toString(),
mUserId);
}
return Secure.putIntForUser(mContext.getContentResolver(),
@@ -128,17 +133,22 @@
* Returns the time when Night display's activation state last changed, or {@code null} if it
* has never been changed.
*/
- public Calendar getLastActivatedTime() {
+ public LocalDateTime getLastActivatedTime() {
final ContentResolver cr = mContext.getContentResolver();
- final long lastActivatedTimeMillis = Secure.getLongForUser(
- cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, -1, mUserId);
- if (lastActivatedTimeMillis < 0) {
- return null;
+ final String lastActivatedTime = Secure.getStringForUser(
+ cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, mUserId);
+ if (lastActivatedTime != null) {
+ try {
+ return LocalDateTime.parse(lastActivatedTime);
+ } catch (DateTimeParseException ignored) {}
+ // Uses the old epoch time.
+ try {
+ return LocalDateTime.ofInstant(
+ Instant.ofEpochMilli(Long.parseLong(lastActivatedTime)),
+ ZoneId.systemDefault());
+ } catch (DateTimeException|NumberFormatException ignored) {}
}
-
- final Calendar lastActivatedTime = Calendar.getInstance();
- lastActivatedTime.setTimeInMillis(lastActivatedTimeMillis);
- return lastActivatedTime;
+ return null;
}
/**
@@ -183,8 +193,10 @@
}
if (getAutoMode() != autoMode) {
- Secure.putLongForUser(mContext.getContentResolver(),
- Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, -1L, mUserId);
+ Secure.putStringForUser(mContext.getContentResolver(),
+ Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+ null,
+ mUserId);
}
return Secure.putIntForUser(mContext.getContentResolver(),
Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mUserId);
@@ -206,7 +218,7 @@
R.integer.config_defaultNightDisplayCustomStartTime);
}
- return LocalTime.valueOf(startTimeValue);
+ return LocalTime.ofSecondOfDay(startTimeValue / 1000);
}
/**
@@ -221,7 +233,7 @@
throw new IllegalArgumentException("startTime cannot be null");
}
return Secure.putIntForUser(mContext.getContentResolver(),
- Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, startTime.toMillis(), mUserId);
+ Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, startTime.toSecondOfDay() * 1000, mUserId);
}
/**
@@ -240,7 +252,7 @@
R.integer.config_defaultNightDisplayCustomEndTime);
}
- return LocalTime.valueOf(endTimeValue);
+ return LocalTime.ofSecondOfDay(endTimeValue / 1000);
}
/**
@@ -255,7 +267,7 @@
throw new IllegalArgumentException("endTime cannot be null");
}
return Secure.putIntForUser(mContext.getContentResolver(),
- Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.toMillis(), mUserId);
+ Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.toSecondOfDay() * 1000, mUserId);
}
/**
@@ -379,106 +391,6 @@
}
/**
- * A time without a time-zone or date.
- */
- public static class LocalTime {
-
- /**
- * The hour of the day from 0 - 23.
- */
- public final int hourOfDay;
- /**
- * The minute within the hour from 0 - 59.
- */
- public final int minute;
-
- public LocalTime(int hourOfDay, int minute) {
- if (hourOfDay < 0 || hourOfDay > 23) {
- throw new IllegalArgumentException("Invalid hourOfDay: " + hourOfDay);
- } else if (minute < 0 || minute > 59) {
- throw new IllegalArgumentException("Invalid minute: " + minute);
- }
-
- this.hourOfDay = hourOfDay;
- this.minute = minute;
- }
-
- /**
- * Returns the first date time corresponding to this local time that occurs before the
- * provided date time.
- *
- * @param time the date time to compare against
- * @return the prior date time corresponding to this local time
- */
- public Calendar getDateTimeBefore(Calendar time) {
- final Calendar c = Calendar.getInstance();
- c.set(Calendar.YEAR, time.get(Calendar.YEAR));
- c.set(Calendar.DAY_OF_YEAR, time.get(Calendar.DAY_OF_YEAR));
-
- c.set(Calendar.HOUR_OF_DAY, hourOfDay);
- c.set(Calendar.MINUTE, minute);
- c.set(Calendar.SECOND, 0);
- c.set(Calendar.MILLISECOND, 0);
-
- // Check if the local time has past, if so return the same time tomorrow.
- if (c.after(time)) {
- c.add(Calendar.DATE, -1);
- }
-
- return c;
- }
-
- /**
- * Returns the first date time corresponding to this local time that occurs after the
- * provided date time.
- *
- * @param time the date time to compare against
- * @return the next date time corresponding to this local time
- */
- public Calendar getDateTimeAfter(Calendar time) {
- final Calendar c = Calendar.getInstance();
- c.set(Calendar.YEAR, time.get(Calendar.YEAR));
- c.set(Calendar.DAY_OF_YEAR, time.get(Calendar.DAY_OF_YEAR));
-
- c.set(Calendar.HOUR_OF_DAY, hourOfDay);
- c.set(Calendar.MINUTE, minute);
- c.set(Calendar.SECOND, 0);
- c.set(Calendar.MILLISECOND, 0);
-
- // Check if the local time has past, if so return the same time tomorrow.
- if (c.before(time)) {
- c.add(Calendar.DATE, 1);
- }
-
- return c;
- }
-
- /**
- * Returns a local time corresponding the given number of milliseconds from midnight.
- *
- * @param millis the number of milliseconds from midnight
- * @return the corresponding local time
- */
- private static LocalTime valueOf(int millis) {
- final int hourOfDay = (millis / 3600000) % 24;
- final int minutes = (millis / 60000) % 60;
- return new LocalTime(hourOfDay, minutes);
- }
-
- /**
- * Returns the local time represented as milliseconds from midnight.
- */
- private int toMillis() {
- return hourOfDay * 3600000 + minute * 60000;
- }
-
- @Override
- public String toString() {
- return String.format(Locale.US, "%02d:%02d", hourOfDay, minute);
- }
- }
-
- /**
* Callback invoked whenever the Night display settings are changed.
*/
public interface Callback {
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index 3a77195..afb1193 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -40,7 +40,7 @@
constexpr int sHistogramSize = ProfileData::HistogramSize();
-static void mergeProfileDataIntoProto(service::GraphicsStatsProto* proto,
+static bool mergeProfileDataIntoProto(service::GraphicsStatsProto* proto,
const std::string& package, int versionCode, int64_t startTime, int64_t endTime,
const ProfileData* data);
static void dumpAsTextToFd(service::GraphicsStatsProto* proto, int outFd);
@@ -159,7 +159,7 @@
return success;
}
-void mergeProfileDataIntoProto(service::GraphicsStatsProto* proto, const std::string& package,
+bool mergeProfileDataIntoProto(service::GraphicsStatsProto* proto, const std::string& package,
int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data) {
if (proto->stats_start() == 0 || proto->stats_start() > startTime) {
proto->set_stats_start(startTime);
@@ -188,23 +188,31 @@
proto->mutable_histogram()->Reserve(sHistogramSize);
creatingHistogram = true;
} else if (proto->histogram_size() != sHistogramSize) {
- LOG_ALWAYS_FATAL("Histogram size mismatch, proto is %d expected %d",
+ ALOGE("Histogram size mismatch, proto is %d expected %d",
proto->histogram_size(), sHistogramSize);
+ return false;
}
int index = 0;
+ bool hitMergeError = false;
data->histogramForEach([&](ProfileData::HistogramEntry entry) {
+ if (hitMergeError) return;
+
service::GraphicsStatsHistogramBucketProto* bucket;
if (creatingHistogram) {
bucket = proto->add_histogram();
bucket->set_render_millis(entry.renderTimeMs);
} else {
bucket = proto->mutable_histogram(index);
- LOG_ALWAYS_FATAL_IF(bucket->render_millis() != static_cast<int32_t>(entry.renderTimeMs),
- "Frame time mistmatch %d vs. %u", bucket->render_millis(), entry.renderTimeMs);
+ if (bucket->render_millis() != static_cast<int32_t>(entry.renderTimeMs)) {
+ ALOGW("Frame time mistmatch %d vs. %u", bucket->render_millis(), entry.renderTimeMs);
+ hitMergeError = true;
+ return;
+ }
}
bucket->set_frame_count(bucket->frame_count() + entry.frameCount);
index++;
});
+ return !hitMergeError;
}
static int32_t findPercentile(service::GraphicsStatsProto* proto, int percentile) {
@@ -221,9 +229,11 @@
void dumpAsTextToFd(service::GraphicsStatsProto* proto, int fd) {
// This isn't a full validation, just enough that we can deref at will
- LOG_ALWAYS_FATAL_IF(proto->package_name().empty()
- || !proto->has_summary(), "package_name() '%s' summary %d",
- proto->package_name().c_str(), proto->has_summary());
+ if (proto->package_name().empty() || !proto->has_summary()) {
+ ALOGW("Skipping dump, invalid package_name() '%s' or summary %d",
+ proto->package_name().c_str(), proto->has_summary());
+ return;
+ }
dprintf(fd, "\nPackage: %s", proto->package_name().c_str());
dprintf(fd, "\nVersion: %d", proto->version_code());
dprintf(fd, "\nStats since: %lldns", proto->stats_start());
@@ -254,14 +264,20 @@
if (!parseFromFile(path, &statsProto)) {
statsProto.Clear();
}
- mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data);
+ if (!mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data)) {
+ return;
+ }
// Although we might not have read any data from the file, merging the existing data
// should always fully-initialize the proto
- LOG_ALWAYS_FATAL_IF(!statsProto.IsInitialized(), "%s",
- statsProto.InitializationErrorString().c_str());
- LOG_ALWAYS_FATAL_IF(statsProto.package_name().empty()
- || !statsProto.has_summary(), "package_name() '%s' summary %d",
- statsProto.package_name().c_str(), statsProto.has_summary());
+ if (!statsProto.IsInitialized()) {
+ ALOGE("proto initialization error %s", statsProto.InitializationErrorString().c_str());
+ return;
+ }
+ if (statsProto.package_name().empty() || !statsProto.has_summary()) {
+ ALOGE("missing package_name() '%s' summary %d",
+ statsProto.package_name().c_str(), statsProto.has_summary());
+ return;
+ }
int outFd = open(path.c_str(), O_CREAT | O_RDWR | O_TRUNC, 0660);
if (outFd <= 0) {
int err = errno;
@@ -312,8 +328,9 @@
if (!path.empty() && !parseFromFile(path, &statsProto)) {
statsProto.Clear();
}
- if (data) {
- mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data);
+ if (data && !mergeProfileDataIntoProto(
+ &statsProto, package, versionCode, startTime, endTime, data)) {
+ return;
}
if (!statsProto.IsInitialized()) {
ALOGW("Failed to load profile data from path '%s' and data %p",
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 2894e89..b072f65 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -202,7 +202,6 @@
audioRoutesChanged = true;
}
- final int mainType = mCurAudioRoutesInfo.mainType;
if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName;
if (mCurAudioRoutesInfo.bluetoothName != null) {
@@ -229,8 +228,11 @@
}
if (audioRoutesChanged) {
- selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, getDefaultSystemAudioRoute(), false);
Log.v(TAG, "Audio routes updated: " + newRoutes + ", a2dp=" + isBluetoothA2dpOn());
+ if (mSelectedRoute == null || mSelectedRoute == mDefaultAudioVideo
+ || mSelectedRoute == mBluetoothA2dpRoute) {
+ selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, getDefaultSystemAudioRoute(), false);
+ }
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index ba9c9e7..6e676bc 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -26,7 +26,6 @@
import android.content.res.Resources;
import android.graphics.drawable.Icon;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -327,6 +326,15 @@
Context context, UserHandle user, Intent intent,
Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles,
boolean usePriority, boolean checkCategory, boolean forceTintExternalIcon) {
+ getTilesForIntent(context, user, intent, addedCache, defaultCategory, outTiles,
+ usePriority, checkCategory, forceTintExternalIcon, false /* shouldUpdateTiles */);
+ }
+
+ public static void getTilesForIntent(
+ Context context, UserHandle user, Intent intent,
+ Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles,
+ boolean usePriority, boolean checkCategory, boolean forceTintExternalIcon,
+ boolean shouldUpdateTiles) {
PackageManager pm = context.getPackageManager();
List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent,
PackageManager.GET_META_DATA, user.getIdentifier());
@@ -364,9 +372,11 @@
updateTileData(context, tile, activityInfo, activityInfo.applicationInfo,
pm, providerMap, forceTintExternalIcon);
if (DEBUG) Log.d(LOG_TAG, "Adding tile " + tile.title);
-
addedCache.put(key, tile);
+ } else if (shouldUpdateTiles) {
+ updateSummaryAndTitle(context, providerMap, tile);
}
+
if (!tile.userHandle.contains(user)) {
tile.userHandle.add(user);
}
@@ -387,7 +397,6 @@
String summary = null;
String keyHint = null;
boolean isIconTintable = false;
- RemoteViews remoteViews = null;
// Get the activity's meta-data
try {
@@ -442,7 +451,8 @@
}
if (metaData.containsKey(META_DATA_PREFERENCE_CUSTOM_VIEW)) {
int layoutId = metaData.getInt(META_DATA_PREFERENCE_CUSTOM_VIEW);
- remoteViews = new RemoteViews(applicationInfo.packageName, layoutId);
+ tile.remoteViews = new RemoteViews(applicationInfo.packageName, layoutId);
+ updateSummaryAndTitle(context, providerMap, tile);
}
}
} catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
@@ -474,7 +484,6 @@
// Suggest a key for this tile
tile.key = keyHint;
tile.isIconTintable = isIconTintable;
- tile.remoteViews = remoteViews;
return true;
}
@@ -482,6 +491,26 @@
return false;
}
+ private static void updateSummaryAndTitle(
+ Context context, Map<String, IContentProvider> providerMap, Tile tile) {
+ if (tile == null || tile.metaData == null
+ || !tile.metaData.containsKey(META_DATA_PREFERENCE_SUMMARY_URI)) {
+ return;
+ }
+
+ String uriString = tile.metaData.getString(META_DATA_PREFERENCE_SUMMARY_URI);
+ Bundle bundle = getBundleFromUri(context, uriString, providerMap);
+ String overrideSummary = getString(bundle, META_DATA_PREFERENCE_SUMMARY);
+ String overrideTitle = getString(bundle, META_DATA_PREFERENCE_TITLE);
+ if (overrideSummary != null) {
+ tile.remoteViews.setTextViewText(android.R.id.summary, overrideSummary);
+ }
+
+ if (overrideTitle != null) {
+ tile.remoteViews.setTextViewText(android.R.id.title, overrideTitle);
+ }
+ }
+
/**
* Gets the icon package name and resource id from content provider.
* @param Context context
@@ -547,37 +576,6 @@
}
}
- public static void updateTileUsingSummaryUri(Context context, final Tile tile) {
- if (tile == null || tile.metaData == null ||
- !tile.metaData.containsKey(META_DATA_PREFERENCE_SUMMARY_URI)) {
- return;
- }
-
- new AsyncTask<Void, Void, Bundle>() {
- @Override
- protected Bundle doInBackground(Void... params) {
- return getBundleFromUri(context,
- tile.metaData.getString(META_DATA_PREFERENCE_SUMMARY_URI), new HashMap<>());
- }
-
- @Override
- protected void onPostExecute(Bundle bundle) {
- if (bundle == null) {
- return;
- }
- final String overrideSummary = getString(bundle, META_DATA_PREFERENCE_SUMMARY);
- final String overrideTitle = getString(bundle, META_DATA_PREFERENCE_TITLE);
-
- if (overrideSummary != null) {
- tile.remoteViews.setTextViewText(android.R.id.summary, overrideSummary);
- }
- if (overrideTitle != null) {
- tile.remoteViews.setTextViewText(android.R.id.title, overrideTitle);
- }
- }
- }.execute();
- }
-
private static String getString(Bundle bundle, String key) {
return bundle == null ? null : bundle.getString(key);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
index 00f32b2..56b8441 100644
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
@@ -195,7 +195,7 @@
intent.setPackage(category.pkg);
}
TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
- mAddCache, null, suggestions, true, false, false);
+ mAddCache, null, suggestions, true, false, false, true /* shouldUpdateTiles */);
filterSuggestions(suggestions, countBefore, isSmartSuggestionEnabled);
if (!category.multiple && suggestions.size() > (countBefore + 1)) {
// If there are too many, remove them all and only re-add the one with the highest
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 3fd7c39..682b85e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -133,7 +133,7 @@
private final Map<String, TimestampedScoredNetwork> mScoredNetworkCache = new HashMap<>();
/** Maximum age of scan results to hold onto while actively scanning. **/
- private static final long MAX_SCAN_RESULT_AGE_MILLIS = 15000;
+ private static final long MAX_SCAN_RESULT_AGE_MILLIS = 25000;
static final String KEY_NETWORKINFO = "key_networkinfo";
static final String KEY_WIFIINFO = "key_wifiinfo";
@@ -426,6 +426,11 @@
}
builder.append(",metered=").append(isMetered());
+ if (WifiTracker.sVerboseLogging) {
+ builder.append(",rssi=").append(mRssi);
+ builder.append(",scan cache size=").append(mScanResultCache.size());
+ }
+
return builder.append(')').toString();
}
@@ -951,6 +956,7 @@
evictOldScanResults();
// TODO: sort list by RSSI or age
+ long nowMs = SystemClock.elapsedRealtime();
for (ScanResult result : mScanResultCache.values()) {
if (result.frequency >= LOWER_FREQ_5GHZ
&& result.frequency <= HIGHER_FREQ_5GHZ) {
@@ -961,7 +967,7 @@
maxRssi5 = result.level;
}
if (num5 <= maxDisplayedScans) {
- scans5GHz.append(verboseScanResultSummary(result, bssid));
+ scans5GHz.append(verboseScanResultSummary(result, bssid, nowMs));
}
} else if (result.frequency >= LOWER_FREQ_24GHZ
&& result.frequency <= HIGHER_FREQ_24GHZ) {
@@ -972,7 +978,7 @@
maxRssi24 = result.level;
}
if (num24 <= maxDisplayedScans) {
- scans24GHz.append(verboseScanResultSummary(result, bssid));
+ scans24GHz.append(verboseScanResultSummary(result, bssid, nowMs));
}
}
}
@@ -1000,7 +1006,7 @@
}
@VisibleForTesting
- /* package */ String verboseScanResultSummary(ScanResult result, String bssid) {
+ /* package */ String verboseScanResultSummary(ScanResult result, String bssid, long nowMs) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(" \n{").append(result.BSSID);
if (result.BSSID.equals(bssid)) {
@@ -1013,6 +1019,8 @@
stringBuilder.append(",")
.append(getSpeedLabel(speed));
}
+ int ageSeconds = (int) (nowMs - result.timestamp / 1000) / 1000;
+ stringBuilder.append(",").append(ageSeconds).append("s");
stringBuilder.append("}");
return stringBuilder.toString();
}
@@ -1209,6 +1217,7 @@
/** Attempt to update the AccessPoint and return true if an update occurred. */
public boolean update(
@Nullable WifiConfiguration config, WifiInfo info, NetworkInfo networkInfo) {
+
boolean updated = false;
final int oldLevel = getLevel();
if (info != null && isInfoForThisAccessPoint(config, info)) {
@@ -1240,6 +1249,7 @@
mAccessPointListener.onLevelChanged(this);
}
}
+
return updated;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 6895550..3c664b0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -624,7 +624,7 @@
String prevSsid = prevAccessPoint.getSsidStr();
boolean found = false;
for (AccessPoint newAccessPoint : accessPoints) {
- if (newAccessPoint.getSsid() != null && newAccessPoint.getSsid()
+ if (newAccessPoint.getSsidStr() != null && newAccessPoint.getSsidStr()
.equals(prevSsid)) {
found = true;
break;
@@ -676,24 +676,23 @@
private void updateNetworkInfo(NetworkInfo networkInfo) {
/* sticky broadcasts can call this when wifi is disabled */
if (!mWifiManager.isWifiEnabled()) {
- mMainHandler.sendEmptyMessage(MainHandler.MSG_PAUSE_SCANNING);
clearAccessPointsAndConditionallyUpdate();
return;
}
- if (networkInfo != null &&
- networkInfo.getDetailedState() == DetailedState.OBTAINING_IPADDR) {
- mMainHandler.sendEmptyMessage(MainHandler.MSG_PAUSE_SCANNING);
- } else {
- mMainHandler.sendEmptyMessage(MainHandler.MSG_RESUME_SCANNING);
- }
-
if (networkInfo != null) {
mLastNetworkInfo = networkInfo;
+ if (DBG()) {
+ Log.d(TAG, "mLastNetworkInfo set: " + mLastNetworkInfo);
+ }
}
WifiConfiguration connectionConfig = null;
+
mLastInfo = mWifiManager.getConnectionInfo();
+ if (DBG()) {
+ Log.d(TAG, "mLastInfo set as: " + mLastInfo);
+ }
if (mLastInfo != null) {
connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId(),
mWifiManager.getConfiguredNetworks());
@@ -717,7 +716,6 @@
}
if (reorder) Collections.sort(mInternalAccessPoints);
-
if (updated) mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
}
}
@@ -866,6 +864,9 @@
if (mScanner != null) {
mScanner.pause();
}
+ synchronized (mLock) {
+ mStaleScanResults = true;
+ }
break;
}
}
@@ -928,6 +929,9 @@
if (mScanner != null) {
mScanner.pause();
}
+ synchronized (mLock) {
+ mStaleScanResults = true;
+ }
}
mMainHandler.obtainMessage(MainHandler.MSG_WIFI_STATE_CHANGED, msg.arg1, 0)
.sendToTarget();
@@ -982,7 +986,7 @@
}
return;
}
- sendEmptyMessageDelayed(0, WIFI_RESCAN_INTERVAL_MS);
+ sendEmptyMessageDelayed(MSG_SCAN, WIFI_RESCAN_INTERVAL_MS);
}
}
@@ -1075,10 +1079,12 @@
oldAccessPoints.put(accessPoint.mId, accessPoint);
}
- if (DBG()) {
- Log.d(TAG, "Starting to copy AP items on the MainHandler");
- }
synchronized (mLock) {
+ if (DBG()) {
+ Log.d(TAG, "Starting to copy AP items on the MainHandler. Internal APs: "
+ + mInternalAccessPoints);
+ }
+
if (notifyListeners) {
notificationMap = mAccessPointListenerAdapter.mPendingNotifications.clone();
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index b99584f..230b200 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -454,7 +454,7 @@
ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
MAX_SCORE_CACHE_AGE_MILLIS);
- String summary = ap.verboseScanResultSummary(scanResults.get(0), null);
+ String summary = ap.verboseScanResultSummary(scanResults.get(0), null, 0);
assertThat(summary.contains(mContext.getString(R.string.speed_label_very_fast))).isTrue();
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index df6587e..7cce648 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -105,15 +105,30 @@
private static final byte SCORE_2 = 15;
private static final int BADGE_2 = AccessPoint.Speed.FAST;
- private static final int CONNECTED_NETWORK_ID = 123;
+ // TODO(b/65594609): Convert mutable Data objects to instance variables / builder pattern
+ private static final int NETWORK_ID_1 = 123;
private static final int CONNECTED_RSSI = -50;
private static final WifiInfo CONNECTED_AP_1_INFO = new WifiInfo();
static {
CONNECTED_AP_1_INFO.setSSID(WifiSsid.createFromAsciiEncoded(SSID_1));
CONNECTED_AP_1_INFO.setBSSID(BSSID_1);
- CONNECTED_AP_1_INFO.setNetworkId(CONNECTED_NETWORK_ID);
+ CONNECTED_AP_1_INFO.setNetworkId(NETWORK_ID_1);
CONNECTED_AP_1_INFO.setRssi(CONNECTED_RSSI);
}
+ private static final WifiConfiguration CONFIGURATION_1 = new WifiConfiguration();
+ static {
+ CONFIGURATION_1.SSID = SSID_1;
+ CONFIGURATION_1.BSSID = BSSID_1;
+ CONFIGURATION_1.networkId = NETWORK_ID_1;
+ }
+
+ private static final int NETWORK_ID_2 = 2;
+ private static final WifiConfiguration CONFIGURATION_2 = new WifiConfiguration();
+ static {
+ CONFIGURATION_2.SSID = SSID_2;
+ CONFIGURATION_2.BSSID = BSSID_2;
+ CONFIGURATION_2.networkId = NETWORK_ID_2;
+ }
@Captor ArgumentCaptor<WifiNetworkScoreCache> mScoreCacheCaptor;
@Mock private ConnectivityManager mockConnectivityManager;
@@ -159,6 +174,8 @@
when(mockWifiManager.isWifiEnabled()).thenReturn(true);
when(mockWifiManager.getScanResults())
.thenReturn(Arrays.asList(buildScanResult1(), buildScanResult2()));
+ when(mockWifiManager.getConfiguredNetworks())
+ .thenReturn(Arrays.asList(CONFIGURATION_1, CONFIGURATION_2));
when(mockCurve1.lookupScore(RSSI_1)).thenReturn(SCORE_1);
@@ -333,8 +350,7 @@
WifiConfiguration configuration = new WifiConfiguration();
configuration.SSID = SSID_1;
configuration.BSSID = BSSID_1;
- configuration.networkId = CONNECTED_NETWORK_ID;
- when(mockWifiManager.getConfiguredNetworks()).thenReturn(Arrays.asList(configuration));
+ configuration.networkId = NETWORK_ID_1;
NetworkInfo networkInfo = new NetworkInfo(
ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
@@ -365,6 +381,24 @@
mainLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
}
+ private void switchToNetwork2(WifiTracker tracker) throws InterruptedException {
+ NetworkInfo networkInfo = new NetworkInfo(
+ ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
+ networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "connecting", "test");
+
+ WifiInfo info = new WifiInfo();
+ info.setSSID(WifiSsid.createFromAsciiEncoded(SSID_2));
+ info.setBSSID(BSSID_2);
+ info.setRssi(CONNECTED_RSSI);
+ info.setNetworkId(NETWORK_ID_2);
+ when(mockWifiManager.getConnectionInfo()).thenReturn(info);
+
+ Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
+ tracker.mReceiver.onReceive(mContext, intent);
+ waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
+ }
+
@Test
public void testAccessPointListenerSetWhenLookingUpUsingScanResults() {
ScanResult scanResult = new ScanResult();
@@ -722,12 +756,6 @@
when(mockWifiManager.getConnectionInfo()).thenReturn(CONNECTED_AP_1_INFO);
- WifiConfiguration configuration = new WifiConfiguration();
- configuration.SSID = SSID_1;
- configuration.BSSID = BSSID_1;
- configuration.networkId = CONNECTED_NETWORK_ID;
- when(mockWifiManager.getConfiguredNetworks()).thenReturn(Arrays.asList(configuration));
-
NetworkInfo networkInfo = new NetworkInfo(
ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "connected", "test");
@@ -881,4 +909,17 @@
assertThat(tracker.isConnected()).isFalse();
verify(mockWifiListener, times(2)).onConnectedChanged();
}
+
+ @Test
+ public void updateNetworkInfoWithNewConnectedNetwork_switchesNetworks() throws Exception {
+ WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
+
+ switchToNetwork2(tracker);
+
+ List<AccessPoint> aps = tracker.getAccessPoints();
+ assertThat(aps.get(0).getSsidStr()).isEqualTo(SSID_2);
+
+ assertThat(aps.get(0).isReachable()).isTrue();
+ assertThat(aps.get(1).isReachable()).isTrue();
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 386e820..e9ca753 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -22,12 +22,10 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.RuntimeEnvironment.application;
@@ -66,7 +64,9 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.internal.ShadowExtractor;
import java.util.ArrayList;
import java.util.Collections;
@@ -75,7 +75,8 @@
@RunWith(RobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH,
- sdk = TestConfig.SDK_VERSION)
+ sdk = TestConfig.SDK_VERSION,
+ shadows = {TileUtilsTest.TileUtilsShadowRemoteViews.class})
public class TileUtilsTest {
@Mock
@@ -420,12 +421,24 @@
}
@Test
- public void updateTileUsingSummaryUri_summaryUriSpecified_shouldOverrideRemoteViewSummary()
+ public void getTilesForIntent_summaryUriSpecified_shouldOverrideRemoteViewSummary()
throws RemoteException {
+ Intent intent = new Intent();
+ Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+ List<Tile> outTiles = new ArrayList<>();
+ List<ResolveInfo> info = new ArrayList<>();
+ ResolveInfo resolveInfo = newInfo(true, null /* category */, null,
+ null, URI_GET_SUMMARY);
+ resolveInfo.activityInfo.metaData.putInt("com.android.settings.custom_view",
+ R.layout.user_preference);
+ info.add(resolveInfo);
+
+ when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+ .thenReturn(info);
+
// Mock the content provider interaction.
Bundle bundle = new Bundle();
- String expectedSummary = "new summary text";
- bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, expectedSummary);
+ bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, "new summary text");
when(mIContentProvider.call(anyString(),
eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY),
any())).thenReturn(bundle);
@@ -434,14 +447,57 @@
when(mContentResolver.acquireUnstableProvider(any(Uri.class)))
.thenReturn(mIContentProvider);
- Tile tile = new Tile();
- tile.metaData = new Bundle();
- tile.metaData.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, URI_GET_SUMMARY);
- tile.remoteViews = mock(RemoteViews.class);
- TileUtils.updateTileUsingSummaryUri(mContext, tile);
- ShadowApplication.runBackgroundTasks();
+ TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+ null /* defaultCategory */, outTiles, false /* usePriority */,
+ false /* checkCategory */, true /* forceTintExternalIcon */);
- verify(tile.remoteViews, times(1)).setTextViewText(anyInt(), eq(expectedSummary));
+ assertThat(outTiles.size()).isEqualTo(1);
+ Tile tile = outTiles.get(0);
+ assertThat(tile.remoteViews).isNotNull();
+ assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference);
+ // Make sure the summary TextView got a new text string.
+ TileUtilsShadowRemoteViews shadowRemoteViews =
+ (TileUtilsShadowRemoteViews) ShadowExtractor.extract(tile.remoteViews);
+ assertThat(shadowRemoteViews.overrideViewId).isEqualTo(android.R.id.summary);
+ assertThat(shadowRemoteViews.overrideText).isEqualTo("new summary text");
+ }
+
+ @Test
+ public void getTilesForIntent_providerUnavailable_shouldNotOverrideRemoteViewSummary()
+ throws RemoteException {
+ Intent intent = new Intent();
+ Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+ List<Tile> outTiles = new ArrayList<>();
+ List<ResolveInfo> info = new ArrayList<>();
+ ResolveInfo resolveInfo = newInfo(true, null /* category */, null,
+ null, URI_GET_SUMMARY);
+ resolveInfo.activityInfo.metaData.putInt("com.android.settings.custom_view",
+ R.layout.user_preference);
+ info.add(resolveInfo);
+
+ when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+ .thenReturn(info);
+
+ // Mock the content provider interaction.
+ Bundle bundle = new Bundle();
+ bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, "new summary text");
+ when(mIContentProvider.call(anyString(),
+ eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY),
+ any())).thenReturn(bundle);
+
+ TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+ null /* defaultCategory */, outTiles, false /* usePriority */,
+ false /* checkCategory */, true /* forceTintExternalIcon */);
+
+ assertThat(outTiles.size()).isEqualTo(1);
+ Tile tile = outTiles.get(0);
+ assertThat(tile.remoteViews).isNotNull();
+ assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference);
+ // Make sure the summary TextView didn't get any text view updates.
+ TileUtilsShadowRemoteViews shadowRemoteViews =
+ (TileUtilsShadowRemoteViews) ShadowExtractor.extract(tile.remoteViews);
+ assertThat(shadowRemoteViews.overrideViewId).isNull();
+ assertThat(shadowRemoteViews.overrideText).isNull();
}
public static ResolveInfo newInfo(boolean systemApp, String category) {
@@ -506,4 +562,16 @@
}
}
+ @Implements(RemoteViews.class)
+ public static class TileUtilsShadowRemoteViews {
+
+ private Integer overrideViewId;
+ private CharSequence overrideText;
+
+ @Implementation
+ public void setTextViewText(int viewId, CharSequence text) {
+ overrideViewId = viewId;
+ overrideText = text;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 8de1d31..2bc0e45c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -15,6 +15,8 @@
*/
package com.android.keyguard;
+import static android.view.Display.INVALID_DISPLAY;
+
import android.app.Presentation;
import android.content.Context;
import android.content.DialogInterface;
@@ -28,16 +30,21 @@
import android.view.View;
import android.view.WindowManager;
+// TODO(multi-display): Support multiple external displays
public class KeyguardDisplayManager {
protected static final String TAG = "KeyguardDisplayManager";
private static boolean DEBUG = KeyguardConstants.DEBUG;
+
+ private final ViewMediatorCallback mCallback;
+ private final MediaRouter mMediaRouter;
+ private final Context mContext;
+
Presentation mPresentation;
- private MediaRouter mMediaRouter;
- private Context mContext;
private boolean mShowing;
- public KeyguardDisplayManager(Context context) {
+ public KeyguardDisplayManager(Context context, ViewMediatorCallback callback) {
mContext = context;
+ mCallback = callback;
mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
}
@@ -90,6 +97,7 @@
};
protected void updateDisplays(boolean showing) {
+ Presentation originalPresentation = mPresentation;
if (showing) {
MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(
MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
@@ -121,6 +129,13 @@
mPresentation = null;
}
}
+
+ // mPresentation is only updated when the display changes
+ if (mPresentation != originalPresentation) {
+ final int displayId = mPresentation != null
+ ? mPresentation.getDisplay().getDisplayId() : INVALID_DISPLAY;
+ mCallback.onSecondaryDisplayShowingChanged(displayId);
+ }
}
private final static class KeyguardPresentation extends Presentation {
diff --git a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
index 327d218..b194de4 100644
--- a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
@@ -88,4 +88,9 @@
* {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}.
*/
int getBouncerPromptReason();
+
+ /**
+ * Invoked when the secondary display showing a keyguard window changes.
+ */
+ void onSecondaryDisplayShowingChanged(int displayId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 3eb68f5..28adca9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard;
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+import static android.view.Display.INVALID_DISPLAY;
import static com.android.internal.telephony.IccCardConstants.State.ABSENT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
@@ -239,6 +240,9 @@
// answer whether the input should be restricted)
private boolean mShowing;
+ // display id of the secondary display on which we have put a keyguard window
+ private int mSecondaryDisplayShowing = INVALID_DISPLAY;
+
/** Cached value of #isInputRestricted */
private boolean mInputRestricted;
@@ -646,6 +650,13 @@
}
return KeyguardSecurityView.PROMPT_REASON_NONE;
}
+
+ @Override
+ public void onSecondaryDisplayShowingChanged(int displayId) {
+ synchronized (KeyguardViewMediator.this) {
+ setShowingLocked(mShowing, displayId, false);
+ }
+ }
};
public void userActivity() {
@@ -670,7 +681,7 @@
filter.addAction(Intent.ACTION_SHUTDOWN);
mContext.registerReceiver(mBroadcastReceiver, filter);
- mKeyguardDisplayManager = new KeyguardDisplayManager(mContext);
+ mKeyguardDisplayManager = new KeyguardDisplayManager(mContext, mViewMediatorCallback);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
@@ -685,7 +696,8 @@
com.android.keyguard.R.bool.config_enableKeyguardService)) {
setShowingLocked(!shouldWaitForProvisioning()
&& !mLockPatternUtils.isLockScreenDisabled(
- KeyguardUpdateMonitor.getCurrentUser()), true /* forceCallbacks */);
+ KeyguardUpdateMonitor.getCurrentUser()),
+ mSecondaryDisplayShowing, true /* forceCallbacks */);
}
mStatusBarKeyguardViewManager =
@@ -1694,10 +1706,10 @@
playSound(mTrustedSoundId);
}
- private void updateActivityLockScreenState(boolean showing) {
+ private void updateActivityLockScreenState(boolean showing, int secondaryDisplayShowing) {
mUiOffloadThread.submit(() -> {
try {
- ActivityManager.getService().setLockScreenShown(showing);
+ ActivityManager.getService().setLockScreenShown(showing, secondaryDisplayShowing);
} catch (RemoteException e) {
}
});
@@ -2060,30 +2072,39 @@
}
private void setShowingLocked(boolean showing) {
- setShowingLocked(showing, false /* forceCallbacks */);
+ setShowingLocked(showing, mSecondaryDisplayShowing, false /* forceCallbacks */);
}
- private void setShowingLocked(boolean showing, boolean forceCallbacks) {
- if (showing != mShowing || forceCallbacks) {
+ private void setShowingLocked(
+ boolean showing, int secondaryDisplayShowing, boolean forceCallbacks) {
+ final boolean notifyDefaultDisplayCallbacks = showing != mShowing || forceCallbacks;
+ if (notifyDefaultDisplayCallbacks || secondaryDisplayShowing != mSecondaryDisplayShowing) {
mShowing = showing;
- int size = mKeyguardStateCallbacks.size();
- for (int i = size - 1; i >= 0; i--) {
- IKeyguardStateCallback callback = mKeyguardStateCallbacks.get(i);
- try {
- callback.onShowingStateChanged(showing);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to call onShowingStateChanged", e);
- if (e instanceof DeadObjectException) {
- mKeyguardStateCallbacks.remove(callback);
- }
+ mSecondaryDisplayShowing = secondaryDisplayShowing;
+ if (notifyDefaultDisplayCallbacks) {
+ notifyDefaultDisplayCallbacks(showing);
+ }
+ updateActivityLockScreenState(showing, secondaryDisplayShowing);
+ }
+ }
+
+ private void notifyDefaultDisplayCallbacks(boolean showing) {
+ int size = mKeyguardStateCallbacks.size();
+ for (int i = size - 1; i >= 0; i--) {
+ IKeyguardStateCallback callback = mKeyguardStateCallbacks.get(i);
+ try {
+ callback.onShowingStateChanged(showing);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to call onShowingStateChanged", e);
+ if (e instanceof DeadObjectException) {
+ mKeyguardStateCallbacks.remove(callback);
}
}
- updateInputRestrictedLocked();
- mUiOffloadThread.submit(() -> {
- mTrustManager.reportKeyguardShowingChanged();
- });
- updateActivityLockScreenState(showing);
}
+ updateInputRestrictedLocked();
+ mUiOffloadThread.submit(() -> {
+ mTrustManager.reportKeyguardShowingChanged();
+ });
}
private void notifyTrustedChangedLocked(boolean trusted) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 84628e7..e28e1c9 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -633,7 +633,7 @@
void destroySessionsLocked() {
if (mSessions.size() == 0) {
- mUi.destroyAll(null, null);
+ mUi.destroyAll(null, null, false);
return;
}
while (mSessions.size() > 0) {
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index f315148..af55807 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -578,9 +578,8 @@
public void run() {
synchronized (mLock) {
if (isCancelledLocked()) {
- // TODO(b/653742740): we should probably return here, but for now we're justing
- // logging to confirm this is the problem if it happens again.
- Slog.e(LOG_TAG, "run() called after canceled: " + mRequest);
+ if (sDebug) Slog.d(LOG_TAG, "run() called after canceled: " + mRequest);
+ return;
}
}
final RemoteFillService remoteService = getService();
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index db0f392..ff6e94b 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -465,7 +465,7 @@
if ((response.getDatasets() == null || response.getDatasets().isEmpty())
&& response.getAuthentication() == null) {
// Response is "empty" from an UI point of view, need to notify client.
- notifyUnavailableToClient();
+ notifyUnavailableToClient(false);
}
synchronized (mLock) {
processResponseLocked(response, requestFlags);
@@ -566,6 +566,10 @@
// FillServiceCallbacks
@Override
public void authenticate(int requestId, int datasetIndex, IntentSender intent, Bundle extras) {
+ if (sDebug) {
+ Slog.d(TAG, "authenticate(): requestId=" + requestId + "; datasetIdx=" + datasetIndex
+ + "; intentSender=" + intent);
+ }
final Intent fillInIntent;
synchronized (mLock) {
if (mDestroyed) {
@@ -574,6 +578,10 @@
return;
}
fillInIntent = createAuthFillInIntentLocked(requestId, extras);
+ if (fillInIntent == null) {
+ forceRemoveSelfLocked();
+ return;
+ }
}
mService.setAuthenticationSelected(id);
@@ -1353,11 +1361,15 @@
}
}
- private void notifyUnavailableToClient() {
+ private void notifyUnavailableToClient(boolean sessionFinished) {
synchronized (mLock) {
- if (!mHasCallback || mCurrentViewId == null) return;
+ if (mCurrentViewId == null) return;
try {
- mClient.notifyNoFillUi(id, mCurrentViewId);
+ if (mHasCallback) {
+ mClient.notifyNoFillUi(id, mCurrentViewId, sessionFinished);
+ } else if (sessionFinished) {
+ mClient.setSessionFinished();
+ }
} catch (RemoteException e) {
Slog.e(TAG, "Error notifying client no fill UI: id=" + mCurrentViewId, e);
}
@@ -1445,7 +1457,7 @@
}
mService.resetLastResponse();
// Nothing to be done, but need to notify client.
- notifyUnavailableToClient();
+ notifyUnavailableToClient(true);
removeSelf();
}
@@ -1564,6 +1576,10 @@
}
void autoFill(int requestId, int datasetIndex, Dataset dataset, boolean generateEvent) {
+ if (sDebug) {
+ Slog.d(TAG, "autoFill(): requestId=" + requestId + "; datasetIdx=" + datasetIndex
+ + "; dataset=" + dataset);
+ }
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#autoFill() rejected - session: "
@@ -1584,10 +1600,14 @@
mService.logDatasetAuthenticationSelected(dataset.getId(), id);
setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH, false);
final Intent fillInIntent = createAuthFillInIntentLocked(requestId, mClientState);
-
+ if (fillInIntent == null) {
+ forceRemoveSelfLocked();
+ return;
+ }
final int authenticationId = AutofillManager.makeAuthenticationId(requestId,
datasetIndex);
startAuthentication(authenticationId, dataset.getAuthentication(), fillInIntent);
+
}
}
@@ -1597,14 +1617,16 @@
}
}
+ // TODO: this should never be null, but we got at least one occurrence, probably due to a race.
+ @Nullable
private Intent createAuthFillInIntentLocked(int requestId, Bundle extras) {
final Intent fillInIntent = new Intent();
final FillContext context = getFillContextByRequestIdLocked(requestId);
if (context == null) {
- // TODO(b/653742740): this will crash system_server. We need to handle it, but we're
- // keeping it crashing for now so we can diagnose when it happens again
- Slog.wtf(TAG, "no FillContext for requestId" + requestId + "; mContexts= " + mContexts);
+ Slog.wtf(TAG, "createAuthFillInIntentLocked(): no FillContext. requestId=" + requestId
+ + "; mContexts= " + mContexts);
+ return null;
}
fillInIntent.putExtra(AutofillManager.EXTRA_ASSIST_STRUCTURE, context.getStructure());
fillInIntent.putExtra(AutofillManager.EXTRA_CLIENT_STATE, extras);
@@ -1744,7 +1766,7 @@
if (mDestroyed) {
return null;
}
- mUi.destroyAll(mPendingSaveUi, this);
+ mUi.destroyAll(mPendingSaveUi, this, true);
mUi.clearCallback(this);
mDestroyed = true;
writeLog(MetricsEvent.AUTOFILL_SESSION_FINISHED);
@@ -1760,7 +1782,16 @@
mPendingSaveUi = null;
removeSelfLocked();
- mUi.destroyAll(mPendingSaveUi, this);
+
+ mHandlerCaller.getHandler().post(() -> {
+ try {
+ mClient.setState(mService.isEnabled(), true, false);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "error updating client state: " + e);
+ }
+ });
+
+ mUi.destroyAll(mPendingSaveUi, this, false);
}
/**
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 434b590..36b95fc 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -275,7 +275,7 @@
if (mCallback != null) {
mCallback.save();
}
- destroySaveUiUiThread(pendingSaveUi);
+ destroySaveUiUiThread(pendingSaveUi, true);
}
@Override
@@ -293,7 +293,7 @@
if (mCallback != null) {
mCallback.cancelSave();
}
- destroySaveUiUiThread(pendingSaveUi);
+ destroySaveUiUiThread(pendingSaveUi, true);
}
@Override
@@ -335,8 +335,8 @@
* Destroy all UI affordances.
*/
public void destroyAll(@Nullable PendingUi pendingSaveUi,
- @Nullable AutoFillUiCallback callback) {
- mHandler.post(() -> destroyAllUiThread(pendingSaveUi, callback));
+ @Nullable AutoFillUiCallback callback, boolean notifyClient) {
+ mHandler.post(() -> destroyAllUiThread(pendingSaveUi, callback, notifyClient));
}
public void dump(PrintWriter pw) {
@@ -379,7 +379,7 @@
}
@android.annotation.UiThread
- private void destroySaveUiUiThread(@Nullable PendingUi pendingSaveUi) {
+ private void destroySaveUiUiThread(@Nullable PendingUi pendingSaveUi, boolean notifyClient) {
if (mSaveUi == null) {
// Calling destroySaveUiUiThread() twice is normal - it usually happens when the
// first call is made after the SaveUI is hidden and the second when the session is
@@ -391,7 +391,7 @@
if (sDebug) Slog.d(TAG, "destroySaveUiUiThread(): " + pendingSaveUi);
mSaveUi.destroy();
mSaveUi = null;
- if (pendingSaveUi != null) {
+ if (pendingSaveUi != null && notifyClient) {
try {
if (sDebug) Slog.d(TAG, "destroySaveUiUiThread(): notifying client");
pendingSaveUi.client.setSaveUiState(pendingSaveUi.id, false);
@@ -403,9 +403,9 @@
@android.annotation.UiThread
private void destroyAllUiThread(@Nullable PendingUi pendingSaveUi,
- @Nullable AutoFillUiCallback callback) {
+ @Nullable AutoFillUiCallback callback, boolean notifyClient) {
hideFillUiUiThread(callback);
- destroySaveUiUiThread(pendingSaveUi);
+ destroySaveUiUiThread(pendingSaveUi, notifyClient);
}
@android.annotation.UiThread
@@ -417,7 +417,7 @@
Slog.d(TAG, "hideAllUiThread(): "
+ "destroying Save UI because pending restoration is finished");
}
- destroySaveUiUiThread(pendingSaveUi);
+ destroySaveUiUiThread(pendingSaveUi, true);
}
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index e0cde72..90ad8a5 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2162,6 +2162,15 @@
}
}
+ if (r.fgRequired) {
+ if (DEBUG_FOREGROUND_SERVICE) {
+ Slog.v(TAG, "Whitelisting " + UserHandle.formatUid(r.appInfo.uid)
+ + " for fg-service launch");
+ }
+ mAm.tempWhitelistUidLocked(r.appInfo.uid,
+ SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch");
+ }
+
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 69285a48..1f8b83e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -713,7 +713,7 @@
public boolean canShowErrorDialogs() {
return mShowDialogs && !mSleeping && !mShuttingDown
- && !mKeyguardController.isKeyguardShowing()
+ && !mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)
&& !(UserManager.isDeviceInDemoMode(mContext)
&& mUserController.getCurrentUser().isDemo());
}
@@ -12614,7 +12614,7 @@
}
@Override
- public void setLockScreenShown(boolean showing) {
+ public void setLockScreenShown(boolean showing, int secondaryDisplayShowing) {
if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
@@ -12624,7 +12624,7 @@
synchronized(this) {
long ident = Binder.clearCallingIdentity();
try {
- mKeyguardController.setKeyguardShown(showing);
+ mKeyguardController.setKeyguardShown(showing, secondaryDisplayShowing);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -24087,7 +24087,7 @@
@Override
public void notifyKeyguardTrustedChanged() {
synchronized (ActivityManagerService.this) {
- if (mKeyguardController.isKeyguardShowing()) {
+ if (mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)) {
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 5b27c9c..b2bbf19 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1176,8 +1176,15 @@
* can be put a secondary screen.
*/
boolean canBeLaunchedOnDisplay(int displayId) {
+ final TaskRecord task = getTask();
+
+ // The resizeability of an Activity's parent task takes precendence over the ActivityInfo.
+ // This allows for a non resizable activity to be launched into a resizeable task.
+ final boolean resizeable =
+ task != null ? task.isResizeable() : supportsResizeableMultiWindow();
+
return service.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
- supportsResizeableMultiWindow(), launchedFromPid, launchedFromUid, info);
+ resizeable, launchedFromPid, launchedFromUid, info);
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 791b2c0..a0817c4 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1980,7 +1980,8 @@
boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible,
boolean isTop) {
final boolean isInPinnedStack = r.getStack().getStackId() == PINNED_STACK_ID;
- final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing();
+ final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing(
+ mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
final boolean keyguardLocked = mStackSupervisor.mKeyguardController.isKeyguardLocked();
final boolean showWhenLocked = r.canShowWhenLocked() && !isInPinnedStack;
final boolean dismissKeyguard = r.hasDismissKeyguardWindows();
@@ -5205,8 +5206,8 @@
voiceInteractor, type);
// add the task to stack first, mTaskPositioner might need the stack association
addTask(task, toTop, "createTaskRecord");
- final boolean isLockscreenShown =
- mService.mStackSupervisor.mKeyguardController.isKeyguardShowing();
+ final boolean isLockscreenShown = mService.mStackSupervisor.mKeyguardController
+ .isKeyguardShowing(mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
if (!layoutTaskInStack(task, info.windowLayout) && mBounds != null && task.isResizeable()
&& !isLockscreenShown) {
task.updateOverrideConfiguration(mBounds);
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index cea80c8..8596113 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -19,6 +19,7 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
@@ -66,6 +67,7 @@
private int mBeforeUnoccludeTransit;
private int mVisibilityTransactionDepth;
private SleepToken mSleepToken;
+ private int mSecondaryDisplayShowing = INVALID_DISPLAY;
KeyguardController(ActivityManagerService service,
ActivityStackSupervisor stackSupervisor) {
@@ -78,10 +80,12 @@
}
/**
- * @return true if Keyguard is showing, not going away, and not being occluded, false otherwise
+ * @return true if Keyguard is showing, not going away, and not being occluded on the given
+ * display, false otherwise
*/
- boolean isKeyguardShowing() {
- return mKeyguardShowing && !mKeyguardGoingAway && !mOccluded;
+ boolean isKeyguardShowing(int displayId) {
+ return mKeyguardShowing && !mKeyguardGoingAway &&
+ (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
}
/**
@@ -94,15 +98,19 @@
/**
* Update the Keyguard showing state.
*/
- void setKeyguardShown(boolean showing) {
- if (showing == mKeyguardShowing) {
+ void setKeyguardShown(boolean showing, int secondaryDisplayShowing) {
+ boolean showingChanged = showing != mKeyguardShowing;
+ if (!showingChanged && secondaryDisplayShowing == mSecondaryDisplayShowing) {
return;
}
mKeyguardShowing = showing;
- dismissDockedStackIfNeeded();
- if (showing) {
- setKeyguardGoingAway(false);
- mDismissalRequested = false;
+ mSecondaryDisplayShowing = secondaryDisplayShowing;
+ if (showingChanged) {
+ dismissDockedStackIfNeeded();
+ if (showing) {
+ setKeyguardGoingAway(false);
+ mDismissalRequested = false;
+ }
}
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
updateKeyguardSleepToken();
@@ -337,9 +345,9 @@
}
private void updateKeyguardSleepToken() {
- if (mSleepToken == null && isKeyguardShowing()) {
+ if (mSleepToken == null && isKeyguardShowing(DEFAULT_DISPLAY)) {
mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
- } else if (mSleepToken != null && !isKeyguardShowing()) {
+ } else if (mSleepToken != null && !isKeyguardShowing(DEFAULT_DISPLAY)) {
mSleepToken.release();
mSleepToken = null;
}
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
index c4911b8..eec2c99 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -48,8 +48,10 @@
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.Calendar;
import java.util.TimeZone;
import com.android.internal.R;
@@ -308,7 +310,7 @@
}
@Override
- public void onCustomStartTimeChanged(NightDisplayController.LocalTime startTime) {
+ public void onCustomStartTimeChanged(LocalTime startTime) {
Slog.d(TAG, "onCustomStartTimeChanged: startTime=" + startTime);
if (mAutoMode != null) {
@@ -317,7 +319,7 @@
}
@Override
- public void onCustomEndTimeChanged(NightDisplayController.LocalTime endTime) {
+ public void onCustomEndTimeChanged(LocalTime endTime) {
Slog.d(TAG, "onCustomEndTimeChanged: endTime=" + endTime);
if (mAutoMode != null) {
@@ -416,6 +418,36 @@
outTemp[10] = blue;
}
+ /**
+ * Returns the first date time corresponding to the local time that occurs before the
+ * provided date time.
+ *
+ * @param compareTime the LocalDateTime to compare against
+ * @return the prior LocalDateTime corresponding to this local time
+ */
+ public static LocalDateTime getDateTimeBefore(LocalTime localTime, LocalDateTime compareTime) {
+ final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
+ compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());
+
+ // Check if the local time has passed, if so return the same time yesterday.
+ return ldt.isAfter(compareTime) ? ldt.minusDays(1) : ldt;
+ }
+
+ /**
+ * Returns the first date time corresponding to this local time that occurs after the
+ * provided date time.
+ *
+ * @param compareTime the LocalDateTime to compare against
+ * @return the next LocalDateTime corresponding to this local time
+ */
+ public static LocalDateTime getDateTimeAfter(LocalTime localTime, LocalDateTime compareTime) {
+ final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
+ compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());
+
+ // Check if the local time has passed, if so return the same time tomorrow.
+ return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
+ }
+
private abstract class AutoMode implements NightDisplayController.Callback {
public abstract void onStart();
@@ -427,10 +459,10 @@
private final AlarmManager mAlarmManager;
private final BroadcastReceiver mTimeChangedReceiver;
- private NightDisplayController.LocalTime mStartTime;
- private NightDisplayController.LocalTime mEndTime;
+ private LocalTime mStartTime;
+ private LocalTime mEndTime;
- private Calendar mLastActivatedTime;
+ private LocalDateTime mLastActivatedTime;
CustomAutoMode() {
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
@@ -443,31 +475,15 @@
}
private void updateActivated() {
- final Calendar now = Calendar.getInstance();
- final Calendar startTime = mStartTime.getDateTimeBefore(now);
- final Calendar endTime = mEndTime.getDateTimeAfter(startTime);
+ final LocalDateTime now = LocalDateTime.now();
+ final LocalDateTime start = getDateTimeBefore(mStartTime, now);
+ final LocalDateTime end = getDateTimeAfter(mEndTime, start);
+ boolean activate = now.isBefore(end);
- boolean activate = now.before(endTime);
if (mLastActivatedTime != null) {
- // Convert mLastActivatedTime to the current timezone if needed.
- final TimeZone currentTimeZone = now.getTimeZone();
- if (!currentTimeZone.equals(mLastActivatedTime.getTimeZone())) {
- final int year = mLastActivatedTime.get(Calendar.YEAR);
- final int dayOfYear = mLastActivatedTime.get(Calendar.DAY_OF_YEAR);
- final int hourOfDay = mLastActivatedTime.get(Calendar.HOUR_OF_DAY);
- final int minute = mLastActivatedTime.get(Calendar.MINUTE);
-
- mLastActivatedTime.setTimeZone(currentTimeZone);
- mLastActivatedTime.set(Calendar.YEAR, year);
- mLastActivatedTime.set(Calendar.DAY_OF_YEAR, dayOfYear);
- mLastActivatedTime.set(Calendar.HOUR_OF_DAY, hourOfDay);
- mLastActivatedTime.set(Calendar.MINUTE, minute);
- }
-
// Maintain the existing activated state if within the current period.
- if (mLastActivatedTime.before(now)
- && mLastActivatedTime.after(startTime)
- && (mLastActivatedTime.after(endTime) || now.before(endTime))) {
+ if (mLastActivatedTime.isBefore(now) && mLastActivatedTime.isAfter(start)
+ && (mLastActivatedTime.isAfter(end) || now.isBefore(end))) {
activate = mController.isActivated();
}
}
@@ -475,14 +491,16 @@
if (mIsActivated == null || mIsActivated != activate) {
mController.setActivated(activate);
}
+
updateNextAlarm(mIsActivated, now);
}
- private void updateNextAlarm(@Nullable Boolean activated, @NonNull Calendar now) {
+ private void updateNextAlarm(@Nullable Boolean activated, @NonNull LocalDateTime now) {
if (activated != null) {
- final Calendar next = activated ? mEndTime.getDateTimeAfter(now)
- : mStartTime.getDateTimeAfter(now);
- mAlarmManager.setExact(AlarmManager.RTC, next.getTimeInMillis(), TAG, this, null);
+ final LocalDateTime next = activated ? getDateTimeAfter(mEndTime, now)
+ : getDateTimeAfter(mStartTime, now);
+ final long millis = next.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
+ mAlarmManager.setExact(AlarmManager.RTC, millis, TAG, this, null);
}
}
@@ -512,18 +530,18 @@
@Override
public void onActivated(boolean activated) {
mLastActivatedTime = mController.getLastActivatedTime();
- updateNextAlarm(activated, Calendar.getInstance());
+ updateNextAlarm(activated, LocalDateTime.now());
}
@Override
- public void onCustomStartTimeChanged(NightDisplayController.LocalTime startTime) {
+ public void onCustomStartTimeChanged(LocalTime startTime) {
mStartTime = startTime;
mLastActivatedTime = null;
updateActivated();
}
@Override
- public void onCustomEndTimeChanged(NightDisplayController.LocalTime endTime) {
+ public void onCustomEndTimeChanged(LocalTime endTime) {
mEndTime = endTime;
mLastActivatedTime = null;
updateActivated();
@@ -552,15 +570,14 @@
}
boolean activate = state.isNight();
- final Calendar lastActivatedTime = mController.getLastActivatedTime();
+ final LocalDateTime lastActivatedTime = mController.getLastActivatedTime();
if (lastActivatedTime != null) {
- final Calendar now = Calendar.getInstance();
- final Calendar sunrise = state.sunrise();
- final Calendar sunset = state.sunset();
-
+ final LocalDateTime now = LocalDateTime.now();
+ final LocalDateTime sunrise = state.sunrise();
+ final LocalDateTime sunset = state.sunset();
// Maintain the existing activated state if within the current period.
- if (lastActivatedTime.before(now)
- && (lastActivatedTime.after(sunrise) ^ lastActivatedTime.after(sunset))) {
+ if (lastActivatedTime.isBefore(now) && (lastActivatedTime.isBefore(sunrise)
+ ^ lastActivatedTime.isBefore(sunset))) {
activate = mController.isActivated();
}
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 0f580d8..4fafe34 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -438,16 +438,7 @@
PackageDexUsage.DexUseInfo dexUseInfo = e.getValue();
pw.println(dex);
pw.increaseIndent();
- for (String isa : dexUseInfo.getLoaderIsas()) {
- String status = null;
- try {
- status = DexFile.getDexFileStatus(path, isa);
- } catch (IOException ioe) {
- status = "[Exception]: " + ioe.getMessage();
- }
- pw.println(isa + ": " + status);
- }
-
+ // TODO(calin): get the status of the oat file (needs installd call)
pw.println("class loader context: " + dexUseInfo.getClassLoaderContext());
if (dexUseInfo.isUsedByOtherApps()) {
pw.println("used be other apps: " + dexUseInfo.getLoadingPackages());
@@ -474,8 +465,9 @@
}
if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
- // If the dex files is used by other apps, we cannot use profile-guided compilation.
- return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
+ // If the dex files is used by other apps, apply the shared filter.
+ return PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+ PackageManagerService.REASON_SHARED);
}
return targetCompilerFilter;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f594b38..b2e0a08 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -577,8 +577,9 @@
public static final int REASON_BACKGROUND_DEXOPT = 3;
public static final int REASON_AB_OTA = 4;
public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 5;
+ public static final int REASON_SHARED = 6;
- public static final int REASON_LAST = REASON_INACTIVE_PACKAGE_DOWNGRADE;
+ public static final int REASON_LAST = REASON_SHARED;
/** All dangerous permission names in the same order as the events in MetricsEvent */
private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
@@ -9803,19 +9804,6 @@
compilerFilter,
dexoptFlags));
- if (pkg.isSystemApp()) {
- // Only dexopt shared secondary dex files belonging to system apps to not slow down
- // too much boot after an OTA.
- int secondaryDexoptFlags = dexoptFlags |
- DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX |
- DexoptOptions.DEXOPT_ONLY_SHARED_DEX;
- mDexManager.dexoptSecondaryDex(new DexoptOptions(
- pkg.packageName,
- compilerFilter,
- secondaryDexoptFlags));
- }
-
- // TODO(shubhamajmera): Record secondary dexopt stats.
switch (primaryDexOptStaus) {
case PackageDexOptimizer.DEX_OPT_PERFORMED:
numberOfPackagesOptimized++;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 1a97a72..19b0d9b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -26,14 +26,19 @@
public class PackageManagerServiceCompilerMapping {
// Names for compilation reasons.
static final String REASON_STRINGS[] = {
- "first-boot", "boot", "install", "bg-dexopt", "ab-ota", "inactive"
+ "first-boot", "boot", "install", "bg-dexopt", "ab-ota", "inactive", "shared"
};
+ static final int REASON_SHARED_INDEX = 6;
+
// Static block to ensure the strings array is of the right length.
static {
if (PackageManagerService.REASON_LAST + 1 != REASON_STRINGS.length) {
throw new IllegalStateException("REASON_STRINGS not correct");
}
+ if (!"shared".equals(REASON_STRINGS[REASON_SHARED_INDEX])) {
+ throw new IllegalStateException("REASON_STRINGS not correct because of shared index");
+ }
}
private static String getSystemPropertyName(int reason) {
@@ -52,11 +57,18 @@
!DexFile.isValidCompilerFilter(sysPropValue)) {
throw new IllegalStateException("Value \"" + sysPropValue +"\" not valid "
+ "(reason " + REASON_STRINGS[reason] + ")");
+ } else if (!isFilterAllowedForReason(reason, sysPropValue)) {
+ throw new IllegalStateException("Value \"" + sysPropValue +"\" not allowed "
+ + "(reason " + REASON_STRINGS[reason] + ")");
}
return sysPropValue;
}
+ private static boolean isFilterAllowedForReason(int reason, String filter) {
+ return reason != REASON_SHARED_INDEX || !DexFile.isProfileGuidedCompilerFilter(filter);
+ }
+
// Check that the properties are set and valid.
// Note: this is done in a separate method so this class can be statically initialized.
static void checkProperties() {
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 50e5e7b..5a5471b 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -1,5 +1,7 @@
package com.android.server.policy.keyguard;
+import static android.view.Display.INVALID_DISPLAY;
+
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
@@ -201,7 +203,10 @@
mKeyguardState.reset();
mHandler.post(() -> {
try {
- ActivityManager.getService().setLockScreenShown(true);
+ // There are no longer any keyguard windows on secondary displays, so pass
+ // INVALID_DISPLAY. All that means is that showWhenLocked activities on
+ // secondary displays now get to show.
+ ActivityManager.getService().setLockScreenShown(true, INVALID_DISPLAY);
} catch (RemoteException e) {
// Local call.
}
diff --git a/services/core/java/com/android/server/twilight/TwilightState.java b/services/core/java/com/android/server/twilight/TwilightState.java
index 30a8ccc..71304a7 100644
--- a/services/core/java/com/android/server/twilight/TwilightState.java
+++ b/services/core/java/com/android/server/twilight/TwilightState.java
@@ -18,7 +18,10 @@
import android.text.format.DateFormat;
-import java.util.Calendar;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.TimeZone;
/**
* The twilight state, consisting of the sunrise and sunset times (in millis) for the current
@@ -45,12 +48,11 @@
}
/**
- * Returns a new {@link Calendar} instance initialized to {@link #sunriseTimeMillis()}.
+ * Returns a new {@link LocalDateTime} instance initialized to {@link #sunriseTimeMillis()}.
*/
- public Calendar sunrise() {
- final Calendar sunrise = Calendar.getInstance();
- sunrise.setTimeInMillis(mSunriseTimeMillis);
- return sunrise;
+ public LocalDateTime sunrise() {
+ final ZoneId zoneId = TimeZone.getDefault().toZoneId();
+ return LocalDateTime.ofInstant(Instant.ofEpochMilli(mSunriseTimeMillis), zoneId);
}
/**
@@ -62,12 +64,11 @@
}
/**
- * Returns a new {@link Calendar} instance initialized to {@link #sunsetTimeMillis()}.
+ * Returns a new {@link LocalDateTime} instance initialized to {@link #sunsetTimeMillis()}.
*/
- public Calendar sunset() {
- final Calendar sunset = Calendar.getInstance();
- sunset.setTimeInMillis(mSunsetTimeMillis);
- return sunset;
+ public LocalDateTime sunset() {
+ final ZoneId zoneId = TimeZone.getDefault().toZoneId();
+ return LocalDateTime.ofInstant(Instant.ofEpochMilli(mSunsetTimeMillis), zoneId);
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
index 58a4456..3a92d63 100644
--- a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
@@ -30,13 +30,14 @@
import android.test.mock.MockContentResolver;
import com.android.internal.app.NightDisplayController;
-import com.android.internal.app.NightDisplayController.LocalTime;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.display.DisplayTransformManager;
import com.android.server.display.NightDisplayService;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -45,6 +46,7 @@
import java.util.Calendar;
import java.util.HashMap;
+import java.time.LocalTime;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -926,11 +928,10 @@
*/
private void setActivated(boolean activated, int lastActivatedTimeOffset) {
mNightDisplayController.setActivated(activated);
-
- final Calendar c = Calendar.getInstance();
- c.add(Calendar.MINUTE, lastActivatedTimeOffset);
- Secure.putLongForUser(mContext.getContentResolver(),
- Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, c.getTimeInMillis(), mUserId);
+ Secure.putStringForUser(mContext.getContentResolver(),
+ Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+ LocalDateTime.now().plusMinutes(lastActivatedTimeOffset).toString(),
+ mUserId);
}
/**
@@ -969,7 +970,7 @@
private static LocalTime getLocalTimeRelativeToNow(int offsetMinutes) {
final Calendar c = Calendar.getInstance();
c.add(Calendar.MINUTE, offsetMinutes);
- return new LocalTime(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
+ return LocalTime.of(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
}
/**
@@ -984,13 +985,27 @@
final LocalTime sunset = getLocalTimeRelativeToNow(sunsetOffset);
final LocalTime sunrise = getLocalTimeRelativeToNow(sunriseOffset);
- final Calendar now = Calendar.getInstance();
- long sunsetMillis = sunset.getDateTimeBefore(now).getTimeInMillis();
- long sunriseMillis = sunrise.getDateTimeBefore(now).getTimeInMillis();
+ final LocalDateTime now = LocalDateTime.now();
+ final ZoneId zoneId = ZoneId.systemDefault();
+
+ long sunsetMillis = NightDisplayService.getDateTimeBefore(sunset, now)
+ .atZone(zoneId)
+ .toInstant()
+ .toEpochMilli();
+ long sunriseMillis = NightDisplayService.getDateTimeBefore(sunrise, now)
+ .atZone(zoneId)
+ .toInstant()
+ .toEpochMilli();
if (sunsetMillis < sunriseMillis) {
- sunsetMillis = sunset.getDateTimeAfter(now).getTimeInMillis();
+ sunsetMillis = NightDisplayService.getDateTimeAfter(sunset, now)
+ .atZone(zoneId)
+ .toInstant()
+ .toEpochMilli();
} else {
- sunriseMillis = sunrise.getDateTimeAfter(now).getTimeInMillis();
+ sunriseMillis = NightDisplayService.getDateTimeAfter(sunrise, now)
+ .atZone(zoneId)
+ .toInstant()
+ .toEpochMilli();
}
return new TwilightState(sunriseMillis, sunsetMillis);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index 2252c85..e51f7a9 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -20,15 +20,19 @@
import static android.view.WindowManagerPolicy.NAV_BAR_LEFT;
import static android.view.WindowManagerPolicy.NAV_BAR_RIGHT;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
+import android.view.Display;
import org.junit.runner.RunWith;
import org.junit.Test;
@@ -46,6 +50,8 @@
private final ComponentName testActivityComponent =
ComponentName.unflattenFromString("com.foo/.BarActivity");
+ private final ComponentName secondaryActivityComponent =
+ ComponentName.unflattenFromString("com.foo/.BarActivity2");
@Test
public void testStackCleanupOnClearingTask() throws Exception {
final ActivityManagerService service = createActivityManagerService();
@@ -131,4 +137,45 @@
record.ensureActivityConfigurationLocked(0 /* globalChanges */, false /* preserveWindow */);
assertEquals(expectedActivityBounds, record.getBounds());
}
+
+
+ @Test
+ public void testCanBeLaunchedOnDisplay() throws Exception {
+ testSupportsLaunchingResizeable(false /*taskPresent*/, true /*taskResizeable*/,
+ true /*activityResizeable*/, true /*expected*/);
+
+ testSupportsLaunchingResizeable(false /*taskPresent*/, true /*taskResizeable*/,
+ false /*activityResizeable*/, false /*expected*/);
+
+ testSupportsLaunchingResizeable(true /*taskPresent*/, false /*taskResizeable*/,
+ true /*activityResizeable*/, false /*expected*/);
+
+ testSupportsLaunchingResizeable(true /*taskPresent*/, true /*taskResizeable*/,
+ false /*activityResizeable*/, true /*expected*/);
+ }
+
+ private void testSupportsLaunchingResizeable(boolean taskPresent, boolean taskResizeable,
+ boolean activityResizeable, boolean expected) {
+ final ActivityManagerService service = createActivityManagerService();
+ service.mSupportsMultiWindow = true;
+
+
+ final TaskRecord task = taskPresent
+ ? createTask(service, testActivityComponent, TEST_STACK_ID) : null;
+
+ if (task != null) {
+ task.setResizeMode(taskResizeable ? ActivityInfo.RESIZE_MODE_RESIZEABLE
+ : ActivityInfo.RESIZE_MODE_UNRESIZEABLE);
+ }
+
+ final ActivityRecord record = createActivity(service, secondaryActivityComponent,
+ task);
+ record.info.resizeMode = activityResizeable ? ActivityInfo.RESIZE_MODE_RESIZEABLE
+ : ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+
+ record.canBeLaunchedOnDisplay(Display.DEFAULT_DISPLAY);
+
+ assertEquals(((TestActivityStackSupervisor) service.mStackSupervisor)
+ .getLastResizeableFromCanPlaceEntityOnDisplay(), expected);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index a6c0cf1..04ddae9 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -163,6 +163,7 @@
*/
protected static class TestActivityStackSupervisor extends ActivityStackSupervisor {
private final ActivityDisplay mDisplay;
+ private boolean mLastResizeable;
public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) {
super(service, looper);
@@ -170,6 +171,22 @@
mDisplay = new ActivityDisplay();
}
+ // TODO: Use Mockito spy instead. Currently not possible due to TestActivityStackSupervisor
+ // access to ActivityDisplay
+ @Override
+ boolean canPlaceEntityOnDisplay(int displayId, boolean resizeable, int callingPid,
+ int callingUid, ActivityInfo activityInfo) {
+ mLastResizeable = resizeable;
+ return super.canPlaceEntityOnDisplay(displayId, resizeable, callingPid, callingUid,
+ activityInfo);
+ }
+
+ // TODO: remove and use Mockito verify once {@link #canPlaceEntityOnDisplay} override is
+ // removed.
+ public boolean getLastResizeableFromCanPlaceEntityOnDisplay() {
+ return mLastResizeable;
+ }
+
// No home stack is set.
@Override
void moveHomeStackToFront(String reason) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 629173d..7a53ef6 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -161,7 +161,7 @@
// Second byte is the MSG_LEN, length of the message
// See 3GPP2 C.S0023 3.4.27
- int size = data[1];
+ int size = data[1] & 0xFF;
// Note: Data may include trailing FF's. That's OK; message
// should still parse correctly.