Merge "Add unit tests for com.android.server.backup.utils"
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index aaaff0c..4e11233 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -26,6 +26,7 @@
import android.app.ActivityManager;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.pm.PackageManager.InstallReason;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.FileBridge;
@@ -948,7 +949,7 @@
/** {@hide} */
public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
/** {@hide} */
- public int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
+ public @InstallReason int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
/** {@hide} */
public long sizeBytes = -1;
/** {@hide} */
@@ -1146,7 +1147,10 @@
}
}
- public void setInstallReason(int installReason) {
+ /**
+ * Set the reason for installing this package.
+ */
+ public void setInstallReason(@InstallReason int installReason) {
this.installReason = installReason;
}
@@ -1236,7 +1240,7 @@
/** {@hide} */
public int mode;
/** {@hide} */
- public int installReason;
+ public @InstallReason int installReason;
/** {@hide} */
public long sizeBytes;
/** {@hide} */
@@ -1324,9 +1328,9 @@
/**
* Return the reason for installing this package.
*
- * @see PackageManager#INSTALL_REASON_UNKNOWN
+ * @return The install reason.
*/
- public int getInstallReason() {
+ public @InstallReason int getInstallReason() {
return installReason;
}
diff --git a/core/java/android/hardware/radio/ITuner.aidl b/core/java/android/hardware/radio/ITuner.aidl
index 68257ff..c08f41f 100644
--- a/core/java/android/hardware/radio/ITuner.aidl
+++ b/core/java/android/hardware/radio/ITuner.aidl
@@ -22,5 +22,12 @@
interface ITuner {
void close();
+ /**
+ * @throws IllegalArgumentException if config is not valid or null
+ */
+ void setConfiguration(in RadioManager.BandConfig config);
+
+ RadioManager.BandConfig getConfiguration();
+
int getProgramInformation(out RadioManager.ProgramInfo[] infoOut);
}
diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java
index 10bbf9f..1156fe8 100644
--- a/core/java/android/hardware/radio/TunerAdapter.java
+++ b/core/java/android/hardware/radio/TunerAdapter.java
@@ -58,14 +58,28 @@
@Override
public int setConfiguration(RadioManager.BandConfig config) {
- // TODO(b/36863239): forward to mTuner
- throw new RuntimeException("Not implemented");
+ try {
+ mTuner.setConfiguration(config);
+ return RadioManager.STATUS_OK;
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Can't set configuration", e);
+ return RadioManager.STATUS_BAD_VALUE;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
@Override
public int getConfiguration(RadioManager.BandConfig[] config) {
- // TODO(b/36863239): forward to mTuner
- throw new RuntimeException("Not implemented");
+ if (config == null || config.length != 1) {
+ throw new IllegalArgumentException("The argument must be an array of length 1");
+ }
+ try {
+ config[0] = mTuner.getConfiguration();
+ return RadioManager.STATUS_OK;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
@Override
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 44addfc..a01b8ed 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -87,16 +87,6 @@
public abstract void setScreenBrightnessOverrideFromWindowManager(int brightness);
/**
- * Used by the window manager to override the button brightness based on the
- * current foreground activity.
- *
- * This method must only be called by the window manager.
- *
- * @param brightness The overridden brightness, or -1 to disable the override.
- */
- public abstract void setButtonBrightnessOverrideFromWindowManager(int brightness);
-
- /**
* Used by the window manager to override the user activity timeout based on the
* current foreground activity. It can only be used to make the timeout shorter
* than usual, not longer.
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 447f280..e063855 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -812,9 +812,11 @@
int timeTotal = -1;
int uncryptTime = -1;
int sourceVersion = -1;
- int temperature_start = -1;
- int temperature_end = -1;
- int temperature_max = -1;
+ int temperatureStart = -1;
+ int temperatureEnd = -1;
+ int temperatureMax = -1;
+ int errorCode = -1;
+ int causeCode = -1;
while ((line = in.readLine()) != null) {
// Here is an example of lines in last_install:
@@ -861,11 +863,15 @@
bytesStashedInMiB = (bytesStashedInMiB == -1) ? scaled :
bytesStashedInMiB + scaled;
} else if (line.startsWith("temperature_start")) {
- temperature_start = scaled;
+ temperatureStart = scaled;
} else if (line.startsWith("temperature_end")) {
- temperature_end = scaled;
+ temperatureEnd = scaled;
} else if (line.startsWith("temperature_max")) {
- temperature_max = scaled;
+ temperatureMax = scaled;
+ } else if (line.startsWith("error")) {
+ errorCode = scaled;
+ } else if (line.startsWith("cause")) {
+ causeCode = scaled;
}
}
@@ -885,14 +891,20 @@
if (bytesStashedInMiB != -1) {
MetricsLogger.histogram(context, "ota_stashed_in_MiBs", bytesStashedInMiB);
}
- if (temperature_start != -1) {
- MetricsLogger.histogram(context, "ota_temperature_start", temperature_start);
+ if (temperatureStart != -1) {
+ MetricsLogger.histogram(context, "ota_temperature_start", temperatureStart);
}
- if (temperature_end != -1) {
- MetricsLogger.histogram(context, "ota_temperature_end", temperature_end);
+ if (temperatureEnd != -1) {
+ MetricsLogger.histogram(context, "ota_temperature_end", temperatureEnd);
}
- if (temperature_max != -1) {
- MetricsLogger.histogram(context, "ota_temperature_max", temperature_max);
+ if (temperatureMax != -1) {
+ MetricsLogger.histogram(context, "ota_temperature_max", temperatureMax);
+ }
+ if (errorCode != -1) {
+ MetricsLogger.histogram(context, "ota_non_ab_error_code", errorCode);
+ }
+ if (causeCode != -1) {
+ MetricsLogger.histogram(context, "ota_non_ab_cause_code", causeCode);
}
} catch (IOException e) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ea58925..1063a46 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6811,7 +6811,8 @@
* Represented as milliseconds from midnight (e.g. 79200000 == 10pm).
* @hide
*/
- public static final String NIGHT_DISPLAY_CUSTOM_START_TIME = "night_display_custom_start_time";
+ public static final String NIGHT_DISPLAY_CUSTOM_START_TIME =
+ "night_display_custom_start_time";
/**
* Custom time when Night display is scheduled to deactivate.
@@ -6821,6 +6822,14 @@
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.
+ * @hide
+ */
+ public static final String NIGHT_DISPLAY_LAST_ACTIVATED_TIME =
+ "night_display_last_activated_time";
+
+ /**
* Names of the service components that the current user has explicitly allowed to
* be a VR mode listener, separated by ':'.
*
@@ -7046,6 +7055,7 @@
NIGHT_DISPLAY_CUSTOM_END_TIME,
NIGHT_DISPLAY_COLOR_TEMPERATURE,
NIGHT_DISPLAY_AUTO_MODE,
+ NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
NIGHT_DISPLAY_ACTIVATED,
SYNC_PARENT_SOUNDS,
CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 4507917..c9d172f 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -33,6 +33,7 @@
import com.android.internal.util.Preconditions;
+import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -310,6 +311,13 @@
/** End index relative to mTrimmedText */
private int mRelativeEnd;
+ /** Information about the last classified text to avoid re-running a query. */
+ private CharSequence mLastClassificationText;
+ private int mLastClassificationSelectionStart;
+ private int mLastClassificationSelectionEnd;
+ private LocaleList mLastClassificationLocales;
+ private SelectionResult mLastClassificationResult;
+
TextClassificationHelper(TextClassifier textClassifier,
CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
reset(textClassifier, text, selectionStart, selectionEnd, locales);
@@ -328,12 +336,25 @@
@WorkerThread
public SelectionResult classifyText() {
- trimText();
- return new SelectionResult(
- mSelectionStart,
- mSelectionEnd,
- mTextClassifier.classifyText(
- mTrimmedText, mRelativeStart, mRelativeEnd, mLocales));
+ if (!Objects.equals(mText, mLastClassificationText)
+ || mSelectionStart != mLastClassificationSelectionStart
+ || mSelectionEnd != mLastClassificationSelectionEnd
+ || !Objects.equals(mLocales, mLastClassificationLocales)) {
+
+ mLastClassificationText = mText;
+ mLastClassificationSelectionStart = mSelectionStart;
+ mLastClassificationSelectionEnd = mSelectionEnd;
+ mLastClassificationLocales = mLocales;
+
+ trimText();
+ mLastClassificationResult = new SelectionResult(
+ mSelectionStart,
+ mSelectionEnd,
+ mTextClassifier.classifyText(
+ mTrimmedText, mRelativeStart, mRelativeEnd, mLocales));
+
+ }
+ return mLastClassificationResult;
}
@WorkerThread
diff --git a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
index 5a570a1..6914e21 100644
--- a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
+++ b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
@@ -361,6 +361,8 @@
// ZERO WIDTH JOINER + regional indicator symbol
state.setByString("| U+1F469 U+200D U+1F1FA");
forwardDelete(state, 0);
+ state.assertEquals("| U+1F1FA");
+ forwardDelete(state, 0);
state.assertEquals("|");
// Regional indicator symbol + end with ZERO WIDTH JOINER
@@ -371,6 +373,8 @@
// Regional indicator symbol + ZERO WIDTH JOINER
state.setByString("| U+1F1FA U+200D U+1F469");
forwardDelete(state, 0);
+ state.assertEquals("| U+1F469");
+ forwardDelete(state, 0);
state.assertEquals("|");
// Start with ZERO WIDTH JOINER + emoji modifier
@@ -391,6 +395,8 @@
// Emoji modifier + ZERO WIDTH JOINER
state.setByString("| U+1F466 U+1F3FB U+200D U+1F469");
forwardDelete(state, 0);
+ state.assertEquals("| U+1F469");
+ forwardDelete(state, 0);
state.assertEquals("|");
// Regional indicator symbol + emoji modifier
diff --git a/packages/CarrierDefaultApp/AndroidManifest.xml b/packages/CarrierDefaultApp/AndroidManifest.xml
index 2ef1cf5..c309133 100644
--- a/packages/CarrierDefaultApp/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/AndroidManifest.xml
@@ -34,6 +34,7 @@
<intent-filter>
<action android:name="com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" />
<action android:name="com.android.internal.telephony.CARRIER_SIGNAL_RESET" />
+ <action android:name="android.intent.action.LOCALE_CHANGED" />
</intent-filter>
</receiver>
<service android:name="com.android.carrierdefaultapp.ProvisionObserver"
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
index 7fd1601..0213306 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
@@ -112,8 +112,6 @@
private static void onShowCaptivePortalNotification(Intent intent, Context context) {
logd("onShowCaptivePortalNotification");
- final NotificationManager notificationMgr = context.getSystemService(
- NotificationManager.class);
Intent portalIntent = new Intent(context, CaptivePortalLoginActivity.class);
portalIntent.putExtras(intent);
portalIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT
@@ -123,7 +121,8 @@
Notification notification = getNotification(context, R.string.portal_notification_id,
R.string.portal_notification_detail, pendingIntent);
try {
- notificationMgr.notify(PORTAL_NOTIFICATION_TAG, PORTAL_NOTIFICATION_ID, notification);
+ context.getSystemService(NotificationManager.class)
+ .notify(PORTAL_NOTIFICATION_TAG, PORTAL_NOTIFICATION_ID, notification);
} catch (NullPointerException npe) {
loge("setNotificationVisible: " + npe);
}
@@ -131,12 +130,11 @@
private static void onShowNoDataServiceNotification(Context context) {
logd("onShowNoDataServiceNotification");
- final NotificationManager notificationMgr = context.getSystemService(
- NotificationManager.class);
Notification notification = getNotification(context, R.string.no_data_notification_id,
R.string.no_data_notification_detail, null);
try {
- notificationMgr.notify(NO_DATA_NOTIFICATION_TAG, NO_DATA_NOTIFICATION_ID, notification);
+ context.getSystemService(NotificationManager.class)
+ .notify(NO_DATA_NOTIFICATION_TAG, NO_DATA_NOTIFICATION_ID, notification);
} catch (NullPointerException npe) {
loge("setNotificationVisible: " + npe);
}
@@ -144,26 +142,16 @@
private static void onCancelAllNotifications(Context context) {
logd("onCancelAllNotifications");
- final NotificationManager notificationMgr = context.getSystemService(
- NotificationManager.class);
- notificationMgr.cancelAll();
+ context.getSystemService(NotificationManager.class).cancelAll();
}
private static Notification getNotification(Context context, int titleId, int textId,
PendingIntent pendingIntent) {
final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
- final NotificationManager notificationManager = context.getSystemService(
- NotificationManager.class);
final Resources resources = context.getResources();
final Bundle extras = Bundle.forPair(Notification.EXTRA_SUBSTITUTE_APP_NAME,
resources.getString(R.string.android_system_label));
- /* Creates the notification channel and registers it with NotificationManager. If a channel
- * with the same ID is already registered, NotificationManager will ignore this call.
- */
- notificationManager.createNotificationChannel(new NotificationChannel(
- NOTIFICATION_CHANNEL_ID_MOBILE_DATA_STATUS,
- resources.getString(R.string.mobile_data_status_notification_channel_name),
- NotificationManager.IMPORTANCE_DEFAULT));
+ createNotificationChannels(context);
Notification.Builder builder = new Notification.Builder(context)
.setContentTitle(resources.getString(titleId))
.setContentText(String.format(resources.getString(textId),
@@ -187,6 +175,19 @@
return builder.build();
}
+ /**
+ * Creates the notification channel and registers it with NotificationManager. Also used to
+ * update an existing channel's name.
+ */
+ static void createNotificationChannels(Context context) {
+ context.getSystemService(NotificationManager.class)
+ .createNotificationChannel(new NotificationChannel(
+ NOTIFICATION_CHANNEL_ID_MOBILE_DATA_STATUS,
+ context.getResources().getString(
+ R.string.mobile_data_status_notification_channel_name),
+ NotificationManager.IMPORTANCE_DEFAULT));
+ }
+
private static void logd(String s) {
Log.d(TAG, s);
}
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierDefaultBroadcastReceiver.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierDefaultBroadcastReceiver.java
index 3fd89d9..3f55ff5 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierDefaultBroadcastReceiver.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierDefaultBroadcastReceiver.java
@@ -32,6 +32,10 @@
Log.d(TAG, "skip carrier actions during provisioning");
return;
}
+ if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
+ CarrierActionUtils.createNotificationChannels(context);
+ return;
+ }
List<Integer> actionList = CustomConfigLoader.loadCarrierActionList(context, intent);
for (int actionIdx : actionList) {
Log.d(TAG, "apply carrier action idx: " + actionIdx);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java
deleted file mode 100644
index 0688481..0000000
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.plugins.doze;
-
-import android.app.PendingIntent;
-import android.content.Context;
-
-import com.android.systemui.plugins.Plugin;
-import com.android.systemui.plugins.annotations.ProvidesInterface;
-
-/**
- * Provides a {@link DozeUi}.
- */
-@ProvidesInterface(action = DozeProvider.ACTION, version = DozeProvider.VERSION)
-public interface DozeProvider extends Plugin {
-
- String ACTION = "com.android.systemui.action.PLUGIN_DOZE";
- int VERSION = 1;
-
- /**
- * Caution: Even if this is called, the DozeUi provided may still be in use until it transitions
- * to DozeState.FINISH
- */
- @Override
- default void onDestroy() {
- }
-
- /**
- * @return the plugin's implementation of DozeUi.
- */
- DozeUi provideDozeUi(Context context, DozeMachine machine, WakeLock wakeLock);
-
- /**
- * If true, the plugin allows the default pulse triggers to fire, otherwise they are disabled.
- */
- default boolean allowDefaultPulseTriggers() {
- return false;
- }
-
- /**
- * Ui for use in DozeMachine.
- */
- interface DozeUi {
- /** Called whenever the DozeMachine state transitions */
- void transitionTo(DozeState oldState, DozeState newState);
- }
-
- /** WakeLock wrapper for testability */
- interface WakeLock {
- /** @see android.os.PowerManager.WakeLock#acquire() */
- void acquire();
- /** @see android.os.PowerManager.WakeLock#release() */
- void release();
- /** @see android.os.PowerManager.WakeLock#wrap(Runnable) */
- Runnable wrap(Runnable r);
- }
-
- /** Plugin version of the DozeMachine's state */
- enum DozeState {
- /** Default state. Transition to INITIALIZED to get Doze going. */
- UNINITIALIZED,
- /** Doze components are set up. Followed by transition to DOZE or DOZE_AOD. */
- INITIALIZED,
- /** Regular doze. Device is asleep and listening for pulse triggers. */
- DOZE,
- /** Always-on doze. Device is asleep, showing UI and listening for pulse triggers. */
- DOZE_AOD,
- /** Pulse has been requested. Device is awake and preparing UI */
- DOZE_REQUEST_PULSE,
- /** Pulse is showing. Device is awake and showing UI. */
- DOZE_PULSING,
- /** Pulse is done showing. Followed by transition to DOZE or DOZE_AOD. */
- DOZE_PULSE_DONE,
- /** Doze is done. DozeService is finished. */
- FINISH,
- /** WakeUp. */
- WAKE_UP,
- }
-
- /** Plugin interface for the doze machine. */
- interface DozeMachine {
- /** Request that the DozeMachine transitions to {@code state} */
- void requestState(DozeState state);
-
- /** Request that the PendingIntent is sent. */
- void requestSendIntent(PendingIntent intent);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 3ae0305..1cc10c2 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -18,24 +18,19 @@
import android.app.AlarmManager;
import android.app.Application;
-import android.app.PendingIntent;
import android.content.Context;
import android.hardware.SensorManager;
import android.os.Handler;
import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.SystemUIApplication;
-import com.android.systemui.plugins.doze.DozeProvider;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.wakelock.DelayedWakeLock;
import com.android.systemui.util.wakelock.WakeLock;
public class DozeFactory {
- private final DozeProvider mDozePlugin;
-
- public DozeFactory(DozeProvider plugin) {
- mDozePlugin = plugin;
+ public DozeFactory() {
}
/** Creates a DozeMachine with its parts for {@code dozeService}. */
@@ -68,89 +63,14 @@
private DozeTriggers createDozeTriggers(Context context, SensorManager sensorManager,
DozeHost host, AmbientDisplayConfiguration config, DozeParameters params,
Handler handler, WakeLock wakeLock, DozeMachine machine) {
- boolean allowPulseTriggers = mDozePlugin == null || mDozePlugin.allowDefaultPulseTriggers();
+ boolean allowPulseTriggers = true;
return new DozeTriggers(context, machine, host, config, params,
sensorManager, handler, wakeLock, allowPulseTriggers);
}
private DozeMachine.Part createDozeUi(Context context, DozeHost host, WakeLock wakeLock,
DozeMachine machine, Handler handler, AlarmManager alarmManager) {
- if (mDozePlugin != null) {
- DozeProvider.DozeUi dozeUi = mDozePlugin.provideDozeUi(context,
- pluginMachine(context, machine, host),
- wakeLock);
- return (oldState, newState) -> {
- dozeUi.transitionTo(pluginState(oldState),
- pluginState(newState));
- };
- } else {
- return new DozeUi(context, alarmManager, machine, wakeLock, host, handler);
- }
- }
-
- private DozeProvider.DozeMachine pluginMachine(Context context, DozeMachine machine,
- DozeHost host) {
- return new DozeProvider.DozeMachine() {
- @Override
- public void requestState(DozeProvider.DozeState state) {
- if (state == DozeProvider.DozeState.WAKE_UP) {
- machine.wakeUp();
- return;
- }
- machine.requestState(implState(state));
- }
-
- @Override
- public void requestSendIntent(PendingIntent intent) {
- host.startPendingIntentDismissingKeyguard(intent);
- }
- };
- }
-
- private DozeMachine.State implState(DozeProvider.DozeState s) {
- switch (s) {
- case UNINITIALIZED:
- return DozeMachine.State.UNINITIALIZED;
- case INITIALIZED:
- return DozeMachine.State.INITIALIZED;
- case DOZE:
- return DozeMachine.State.DOZE;
- case DOZE_AOD:
- return DozeMachine.State.DOZE_AOD;
- case DOZE_REQUEST_PULSE:
- return DozeMachine.State.DOZE_REQUEST_PULSE;
- case DOZE_PULSING:
- return DozeMachine.State.DOZE_PULSING;
- case DOZE_PULSE_DONE:
- return DozeMachine.State.DOZE_PULSE_DONE;
- case FINISH:
- return DozeMachine.State.FINISH;
- default:
- throw new IllegalArgumentException("Unknown state: " + s);
- }
- }
-
- private DozeProvider.DozeState pluginState(DozeMachine.State s) {
- switch (s) {
- case UNINITIALIZED:
- return DozeProvider.DozeState.UNINITIALIZED;
- case INITIALIZED:
- return DozeProvider.DozeState.INITIALIZED;
- case DOZE:
- return DozeProvider.DozeState.DOZE;
- case DOZE_AOD:
- return DozeProvider.DozeState.DOZE_AOD;
- case DOZE_REQUEST_PULSE:
- return DozeProvider.DozeState.DOZE_REQUEST_PULSE;
- case DOZE_PULSING:
- return DozeProvider.DozeState.DOZE_PULSING;
- case DOZE_PULSE_DONE:
- return DozeProvider.DozeState.DOZE_PULSE_DONE;
- case FINISH:
- return DozeProvider.DozeState.FINISH;
- default:
- throw new IllegalArgumentException("Unknown state: " + s);
- }
+ return new DozeUi(context, alarmManager, machine, wakeLock, host, handler);
}
public static DozeHost getHost(DozeService service) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 8181c4e8..3271caf 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -24,7 +24,6 @@
import com.android.systemui.Dependency;
import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginManager;
-import com.android.systemui.plugins.doze.DozeProvider;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -50,9 +49,7 @@
return;
}
- DozeProvider provider = Dependency.get(PluginManager.class)
- .getOneShotPlugin(DozeProvider.class);
- mDozeMachine = new DozeFactory(provider).assembleMachine(this);
+ mDozeMachine = new DozeFactory().assembleMachine(this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index b89b062..28895d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -4062,7 +4062,10 @@
public void showKeyguard() {
mKeyguardRequested = true;
- updateIsKeyguard();
+ // Unconditionally show keyguard again. There's some logic that relies on this
+ // being called even when the keyguard is already showing, e.g. for updating
+ // sensitiveness of notifications and making sure the panels are expanded.
+ showKeyguardImpl();
}
public boolean hideKeyguard() {
@@ -4075,7 +4078,10 @@
// there's no surface we can show to the user.
boolean keyguardForDozing = mDozingRequested && !mDeviceInteractive;
boolean shouldBeKeyguard = mKeyguardRequested || keyguardForDozing;
- if (shouldBeKeyguard && !mIsKeyguard) {
+ if (keyguardForDozing) {
+ updatePanelExpansionForKeyguard();
+ }
+ if (shouldBeKeyguard) {
showKeyguardImpl();
} else if (!shouldBeKeyguard && mIsKeyguard) {
return hideKeyguardImpl();
@@ -4103,11 +4109,7 @@
// Keyguard.
mNotificationPanel.setTouchDisabled(true);
}
- if (mState == StatusBarState.KEYGUARD) {
- instantExpandNotificationsPanel();
- } else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
- instantCollapseNotificationPanel();
- }
+ updatePanelExpansionForKeyguard();
mLeaveOpenOnKeyguardHide = false;
if (mDraggedDownRow != null) {
mDraggedDownRow.setUserLocked(false);
@@ -4118,6 +4120,14 @@
mAssistManager.onLockscreenShown();
}
+ private void updatePanelExpansionForKeyguard() {
+ if (mState == StatusBarState.KEYGUARD) {
+ instantExpandNotificationsPanel();
+ } else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
+ instantCollapseNotificationPanel();
+ }
+ }
+
private void onLaunchTransitionFadingEnded() {
mNotificationPanel.setAlpha(1.0f);
mNotificationPanel.onAffordanceLaunchEnded();
@@ -4506,7 +4516,6 @@
}
private void instantExpandNotificationsPanel() {
-
// Make our window larger and the panel expanded.
makeExpandedVisible(true);
mNotificationPanel.expand(false /* animate */);
@@ -5087,6 +5096,7 @@
mDozingRequested = true;
DozeLog.traceDozing(mContext, mDozing);
updateDozing();
+
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
index 23c51d2..edf294e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
@@ -20,10 +20,17 @@
import android.os.PowerManager;
import android.support.annotation.VisibleForTesting;
-import com.android.systemui.plugins.doze.DozeProvider;
-
/** WakeLock wrapper for testability */
-public interface WakeLock extends DozeProvider.WakeLock {
+public interface WakeLock {
+
+ /** @see android.os.PowerManager.WakeLock#acquire() */
+ void acquire();
+
+ /** @see android.os.PowerManager.WakeLock#release() */
+ void release();
+
+ /** @see android.os.PowerManager.WakeLock#wrap(Runnable) */
+ Runnable wrap(Runnable r);
static WakeLock createPartial(Context context, String tag) {
return wrap(createPartialInner(context, tag));
diff --git a/preloaded-classes b/preloaded-classes
index 892c593..493e980 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1820,6 +1820,7 @@
android.text.GetChars
android.text.GraphicsOperations
android.text.Html
+android.text.Html$HtmlParser
android.text.Hyphenator
android.text.InputFilter
android.text.InputType
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 04a54a7..45ecbdb 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -3866,9 +3866,14 @@
writeApkToBackup(mPackage, output);
}
+ final boolean isSharedStorage =
+ mPackage.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
+ final long timeout = isSharedStorage ?
+ TIMEOUT_SHARED_BACKUP_INTERVAL : TIMEOUT_FULL_BACKUP_INTERVAL;
+
if (DEBUG) Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName);
- prepareOperationTimeout(mToken, TIMEOUT_FULL_BACKUP_INTERVAL,
- mTimeoutMonitor /* in parent class */, OP_TYPE_BACKUP_WAIT);
+ prepareOperationTimeout(mToken, timeout, mTimeoutMonitor /* in parent class */,
+ OP_TYPE_BACKUP_WAIT);
mAgent.doFullBackup(mPipe, mQuota, mToken, mBackupManagerBinder);
} catch (IOException e) {
Slog.e(TAG, "Error running full backup for " + mPackage.packageName);
@@ -7554,9 +7559,12 @@
if (okay) {
boolean agentSuccess = true;
long toCopy = info.size;
+ final boolean isSharedStorage = pkg.equals(SHARED_BACKUP_AGENT_PACKAGE);
+ final long timeout = isSharedStorage ?
+ TIMEOUT_SHARED_BACKUP_INTERVAL : TIMEOUT_RESTORE_INTERVAL;
final int token = generateRandomIntegerToken();
try {
- prepareOperationTimeout(token, TIMEOUT_RESTORE_INTERVAL, null,
+ prepareOperationTimeout(token, timeout, null,
OP_TYPE_RESTORE_WAIT);
if (FullBackup.OBB_TREE_TOKEN.equals(info.domain)) {
if (DEBUG) Slog.d(TAG, "Restoring OBB file for " + pkg
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index a7ec1b3..811b741 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -212,7 +212,7 @@
// Timeout intervals for agent backup & restore operations
public static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000;
public static final long TIMEOUT_FULL_BACKUP_INTERVAL = 5 * 60 * 1000;
- private static final long TIMEOUT_SHARED_BACKUP_INTERVAL = 30 * 60 * 1000;
+ public static final long TIMEOUT_SHARED_BACKUP_INTERVAL = 30 * 60 * 1000;
public static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000;
public static final long TIMEOUT_RESTORE_FINISHED_INTERVAL = 30 * 1000;
diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
index 72eeea0..47ae206 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
@@ -120,13 +120,20 @@
writeApkToBackup(mPackage, output);
}
+ final boolean isSharedStorage =
+ mPackage.packageName.equals(
+ RefactoredBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE);
+ final long timeout = isSharedStorage ?
+ RefactoredBackupManagerService.TIMEOUT_SHARED_BACKUP_INTERVAL :
+ RefactoredBackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL;
+
if (RefactoredBackupManagerService.DEBUG) {
Slog.d(RefactoredBackupManagerService.TAG,
"Calling doFullBackup() on " + mPackage.packageName);
}
backupManagerService
.prepareOperationTimeout(mToken,
- RefactoredBackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL,
+ timeout,
mTimeoutMonitor /* in parent class */,
RefactoredBackupManagerService.OP_TYPE_BACKUP_WAIT);
mAgent.doFullBackup(mPipe, mQuota, mToken,
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index f5ed2fd..1d5be28 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -373,9 +373,14 @@
if (okay) {
boolean agentSuccess = true;
long toCopy = info.size;
+ final boolean isSharedStorage = pkg.equals(
+ RefactoredBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE);
+ final long timeout = isSharedStorage ?
+ RefactoredBackupManagerService.TIMEOUT_SHARED_BACKUP_INTERVAL :
+ RefactoredBackupManagerService.TIMEOUT_RESTORE_INTERVAL;
try {
backupManagerService.prepareOperationTimeout(token,
- RefactoredBackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL,
+ timeout,
mMonitorTask,
RefactoredBackupManagerService.OP_TYPE_RESTORE_WAIT);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 19b9b45..089217c 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -953,7 +953,7 @@
// If we are not able to proceed, disassociate the activity from the task. Leaving an
// activity in an incomplete state can lead to issues, such as performing operations
// without a window container.
- if (result != START_SUCCESS && mStartActivity.getTask() != null) {
+ if (result < START_SUCCESS && mStartActivity.getTask() != null) {
mStartActivity.getTask().removeActivity(mStartActivity);
}
mService.mWindowManager.continueSurfaceLayout();
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
index d1275bb..7849896 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -47,7 +47,6 @@
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
-import com.android.server.vr.VrManagerService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.Calendar;
@@ -62,7 +61,6 @@
implements NightDisplayController.Callback {
private static final String TAG = "NightDisplayService";
- private static final boolean DEBUG = false;
/**
* The transition time, in milliseconds, for Night Display to turn on/off.
@@ -151,8 +149,9 @@
@Override
public void onBootPhase(int phase) {
- if (phase == PHASE_SYSTEM_SERVICES_READY) {
- IVrManager vrManager = (IVrManager) getBinderService(Context.VR_SERVICE);
+ if (phase >= PHASE_SYSTEM_SERVICES_READY) {
+ final IVrManager vrManager = IVrManager.Stub.asInterface(
+ getBinderService(Context.VR_SERVICE));
if (vrManager != null) {
try {
vrManager.registerListener(mVrStateCallbacks);
@@ -160,7 +159,9 @@
Slog.e(TAG, "Failed to register VR mode state listener: " + e);
}
}
- } else if (phase == PHASE_BOOT_COMPLETED) {
+ }
+
+ if (phase >= PHASE_BOOT_COMPLETED) {
mBootCompleted = true;
// Register listeners now that boot is complete.
@@ -284,12 +285,18 @@
if (mIsActivated == null || mIsActivated != activated) {
Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display");
- if (mAutoMode != null) {
- mAutoMode.onActivated(activated);
+ if (mIsActivated != null) {
+ Secure.putLongForUser(getContext().getContentResolver(),
+ Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, System.currentTimeMillis(),
+ mCurrentUser);
}
mIsActivated = activated;
+ if (mAutoMode != null) {
+ mAutoMode.onActivated(activated);
+ }
+
applyTint(false);
}
}
@@ -401,7 +408,7 @@
* Set the color transformation {@code MATRIX_NIGHT} to the given color temperature.
*
* @param colorTemperature color temperature in Kelvin
- * @param outTemp the 4x4 display transformation matrix for that color temperature
+ * @param outTemp the 4x4 display transformation matrix for that color temperature
*/
private void setMatrix(int colorTemperature, float[] outTemp) {
if (outTemp.length != 16) {
@@ -423,8 +430,22 @@
outTemp[10] = blue;
}
+ private Calendar getLastActivatedTime() {
+ final ContentResolver cr = getContext().getContentResolver();
+ final long lastActivatedTimeMillis = Secure.getLongForUser(
+ cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, -1, mCurrentUser);
+ if (lastActivatedTimeMillis < 0) {
+ return null;
+ }
+
+ final Calendar lastActivatedTime = Calendar.getInstance();
+ lastActivatedTime.setTimeInMillis(lastActivatedTimeMillis);
+ return lastActivatedTime;
+ }
+
private abstract class AutoMode implements NightDisplayController.Callback {
public abstract void onStart();
+
public abstract void onStop();
}
@@ -438,7 +459,7 @@
private Calendar mLastActivatedTime;
- public CustomAutoMode() {
+ CustomAutoMode() {
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
mTimeChangedReceiver = new BroadcastReceiver() {
@Override
@@ -452,10 +473,10 @@
final Calendar now = Calendar.getInstance();
final Calendar startTime = mStartTime.getDateTimeBefore(now);
final Calendar endTime = mEndTime.getDateTimeAfter(startTime);
- final boolean activated = now.before(endTime);
- boolean setActivated = mIsActivated == null || mLastActivatedTime == null;
- if (!setActivated && mIsActivated != activated) {
+ 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);
@@ -470,17 +491,16 @@
mLastActivatedTime.set(Calendar.MINUTE, minute);
}
- if (mIsActivated) {
- setActivated = now.before(mStartTime.getDateTimeBefore(mLastActivatedTime))
- || now.after(mEndTime.getDateTimeAfter(mLastActivatedTime));
- } else {
- setActivated = now.before(mEndTime.getDateTimeBefore(mLastActivatedTime))
- || now.after(mStartTime.getDateTimeAfter(mLastActivatedTime));
+ // Maintain the existing activated state if within the current period.
+ if (mLastActivatedTime.before(now)
+ && mLastActivatedTime.after(startTime)
+ && (mLastActivatedTime.after(endTime) || now.before(endTime))) {
+ activate = mController.isActivated();
}
}
- if (setActivated) {
- mController.setActivated(activated);
+ if (mIsActivated == null || mIsActivated != activate) {
+ mController.setActivated(activate);
}
updateNextAlarm(mIsActivated, now);
}
@@ -502,6 +522,8 @@
mStartTime = mController.getCustomStartTime();
mEndTime = mController.getCustomEndTime();
+ mLastActivatedTime = getLastActivatedTime();
+
// Force an update to initialize state.
updateActivated();
}
@@ -516,11 +538,8 @@
@Override
public void onActivated(boolean activated) {
- final Calendar now = Calendar.getInstance();
- if (mIsActivated != null) {
- mLastActivatedTime = now;
- }
- updateNextAlarm(activated, now);
+ mLastActivatedTime = getLastActivatedTime();
+ updateNextAlarm(activated, Calendar.getInstance());
}
@Override
@@ -550,33 +569,33 @@
private Calendar mLastActivatedTime;
- public TwilightAutoMode() {
+ TwilightAutoMode() {
mTwilightManager = getLocalService(TwilightManager.class);
}
private void updateActivated(TwilightState state) {
- final boolean isNight = state != null && state.isNight();
- boolean setActivated = mIsActivated == null || mIsActivated != isNight;
- if (setActivated && state != null && mLastActivatedTime != null) {
+ boolean activate = state != null && state.isNight();
+ if (state != null && mLastActivatedTime != null) {
+ final Calendar now = Calendar.getInstance();
final Calendar sunrise = state.sunrise();
final Calendar sunset = state.sunset();
- if (sunrise.before(sunset)) {
- setActivated = mLastActivatedTime.before(sunrise)
- || mLastActivatedTime.after(sunset);
- } else {
- setActivated = mLastActivatedTime.before(sunset)
- || mLastActivatedTime.after(sunrise);
+
+ // Maintain the existing activated state if within the current period.
+ if (mLastActivatedTime.before(now)
+ && (mLastActivatedTime.after(sunrise) ^ mLastActivatedTime.after(sunset))) {
+ activate = mController.isActivated();
}
}
- if (setActivated) {
- mController.setActivated(isNight);
+ if (mIsActivated == null || mIsActivated != activate) {
+ mController.setActivated(activate);
}
}
@Override
public void onStart() {
mTwilightManager.registerListener(this, mHandler);
+ mLastActivatedTime = getLastActivatedTime();
// Force an update to initialize state.
updateActivated(mTwilightManager.getLastTwilightState());
@@ -591,7 +610,7 @@
@Override
public void onActivated(boolean activated) {
if (mIsActivated != null) {
- mLastActivatedTime = Calendar.getInstance();
+ mLastActivatedTime = getLastActivatedTime();
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index 63647ff..8caaaa1 100644
--- a/services/core/java/com/android/server/notification/NotificationComparator.java
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -73,11 +73,13 @@
// Next: sufficiently import person to person communication
boolean leftPeople = isImportantPeople(left);
boolean rightPeople = isImportantPeople(right);
+ final int contactAffinityComparison =
+ Float.compare(left.getContactAffinity(), right.getContactAffinity());
if (leftPeople && rightPeople){
// by contact proximity, close to far. if same proximity, check further fields.
- if (Float.compare(left.getContactAffinity(), right.getContactAffinity()) != 0) {
- return -1 * Float.compare(left.getContactAffinity(), right.getContactAffinity());
+ if (contactAffinityComparison != 0) {
+ return -1 * contactAffinityComparison;
}
} else if (leftPeople != rightPeople) {
// People, messaging higher than non-messaging
@@ -91,6 +93,11 @@
return -1 * Integer.compare(leftImportance, rightImportance);
}
+ // by contact proximity, close to far. if same proximity, check further fields.
+ if (contactAffinityComparison != 0) {
+ return -1 * contactAffinityComparison;
+ }
+
// Whether or not the notification can bypass DND.
final int leftPackagePriority = left.getPackagePriority();
final int rightPackagePriority = right.getPackagePriority();
diff --git a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
index 31ed350..f92bf3d 100644
--- a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
+++ b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
@@ -19,6 +19,7 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
+import android.net.Uri;
import android.service.notification.NotificationListenerService;
import android.util.Log;
import android.util.Slog;
@@ -46,12 +47,13 @@
}
if (record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT) {
- final Notification notification = record.getNotification();
- if ((notification.defaults & Notification.DEFAULT_VIBRATE) != 0 ||
- notification.vibrate != null ||
- (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
- notification.sound != null ||
- notification.fullScreenIntent != null) {
+ if (record.getSound() != null && record.getSound() != Uri.EMPTY) {
+ record.setRecentlyIntrusive(true);
+ }
+ if (record.getVibration() != null) {
+ record.setRecentlyIntrusive(true);
+ }
+ if (record.getNotification().fullScreenIntent != null) {
record.setRecentlyIntrusive(true);
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d8d099b..48d11c3 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2869,7 +2869,8 @@
adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
System.currentTimeMillis());
summaryRecord = new NotificationRecord(getContext(), summarySbn,
- notificationRecord.getChannel());
+ notificationRecord.getChannel(), mRankingHelper.supportsChannels(
+ summarySbn.getPackageName(), summarySbn.getUid()));
summaries.put(pkg, summarySbn.getKey());
}
}
@@ -3189,12 +3190,6 @@
final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
notificationUid, channelId, false /* includeDeleted */);
if (channel == null) {
- // STOPSHIP TODO: remove before release - should always throw without a valid channel.
- if (channelId == null) {
- Log.e(TAG, "Cannot post notification without channel ID when targeting O "
- + " - notification=" + notification);
- return;
- }
final String noChannelStr = "No Channel found for "
+ "pkg=" + pkg
+ ", channelId=" + channelId
@@ -3211,18 +3206,13 @@
"Failed to post notification on channel \"" + channelId + "\"\n" +
"See log for more details");
return;
- } else if (channelId == null && shouldWarnUseChannels(pkg, notificationUid)) {
- // STOPSHIP TODO: remove once default channel is removed for all apps that target O.
- Log.e(TAG, "Developer Warning for package " + pkg
- + ", no channel specified for posted notification: " + notification);
- doDebugOnlyToast("Developer warning for package \"" + pkg + "\"\n" +
- "Posted notification should specify a channel");
}
final StatusBarNotification n = new StatusBarNotification(
pkg, opPkg, id, tag, notificationUid, callingPid, notification,
user, null, System.currentTimeMillis());
- final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
+ final NotificationRecord r = new NotificationRecord(getContext(), n, channel,
+ mRankingHelper.supportsChannels(pkg, notificationUid));
if (!checkDisqualifyingFeatures(userId, notificationUid, id,tag, r)) {
return;
@@ -3259,19 +3249,6 @@
}
}
- // STOPSHIP - Remove once RankingHelper deletes default channel for all apps targeting O.
- private boolean shouldWarnUseChannels(String pkg, int uid) {
- try {
- final int userId = UserHandle.getUserId(uid);
- final ApplicationInfo applicationInfo =
- mPackageManagerClient.getApplicationInfoAsUser(pkg, 0, userId);
- return applicationInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1;
- } catch (NameNotFoundException e) {
- Slog.e(TAG, e.toString());
- return false;
- }
- }
-
private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
// The system can post notifications on behalf of any package it wants
if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index b51a4d1..90257da 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -115,7 +115,7 @@
private int mSuppressedVisualEffects = 0;
private String mUserExplanation;
private String mPeopleExplanation;
- private boolean mPreChannelsNotification = true;
+ private boolean mSupportsChannels = false;
private Uri mSound;
private long[] mVibration;
private AudioAttributes mAttributes;
@@ -128,7 +128,7 @@
@VisibleForTesting
public NotificationRecord(Context context, StatusBarNotification sbn,
- NotificationChannel channel)
+ NotificationChannel channel, boolean supportsChannels)
{
this.sbn = sbn;
mOriginalFlags = sbn.getNotification().flags;
@@ -138,7 +138,7 @@
mContext = context;
stats = new NotificationUsageStats.SingleNotificationStats();
mChannel = channel;
- mPreChannelsNotification = isPreChannelsNotification();
+ mSupportsChannels = supportsChannels;
mSound = calculateSound();
mVibration = calculateVibration();
mAttributes = calculateAttributes();
@@ -146,27 +146,11 @@
mLight = calculateLights();
}
- private boolean isPreChannelsNotification() {
- try {
- if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(getChannel().getId())) {
- final ApplicationInfo applicationInfo =
- mContext.getPackageManager().getApplicationInfoAsUser(sbn.getPackageName(),
- 0, UserHandle.getUserId(sbn.getUid()));
- if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
- return true;
- }
- }
- } catch (NameNotFoundException e) {
- Slog.e(TAG, "Can't find package", e);
- }
- return false;
- }
-
private Uri calculateSound() {
final Notification n = sbn.getNotification();
Uri sound = mChannel.getSound();
- if (mPreChannelsNotification && (getChannel().getUserLockedFields()
+ if (!mSupportsChannels && (getChannel().getUserLockedFields()
& NotificationChannel.USER_LOCKED_SOUND) == 0) {
final boolean useDefaultSound = (n.defaults & Notification.DEFAULT_SOUND) != 0;
@@ -191,7 +175,7 @@
: defaultLightColor;
Light light = getChannel().shouldShowLights() ? new Light(channelLightColor,
defaultLightOn, defaultLightOff) : null;
- if (mPreChannelsNotification
+ if (!mSupportsChannels
&& (getChannel().getUserLockedFields()
& NotificationChannel.USER_LOCKED_LIGHTS) == 0) {
final Notification notification = sbn.getNotification();
@@ -222,7 +206,7 @@
} else {
vibration = null;
}
- if (mPreChannelsNotification
+ if (!mSupportsChannels
&& (getChannel().getUserLockedFields()
& NotificationChannel.USER_LOCKED_VIBRATION) == 0) {
final Notification notification = sbn.getNotification();
@@ -244,7 +228,7 @@
attributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
}
- if (mPreChannelsNotification
+ if (!mSupportsChannels
&& (getChannel().getUserLockedFields()
& NotificationChannel.USER_LOCKED_SOUND) == 0) {
if (n.audioAttributes != null) {
@@ -293,7 +277,7 @@
stats.requestedImportance = requestedImportance;
stats.isNoisy = mSound != null || mVibration != null;
- if (mPreChannelsNotification
+ if (!mSupportsChannels
&& (importance == IMPORTANCE_UNSPECIFIED
|| (getChannel().getUserLockedFields()
& NotificationChannel.USER_LOCKED_IMPORTANCE) == 0)) {
@@ -460,7 +444,7 @@
pw.println(prefix + "mVisibleSinceMs=" + mVisibleSinceMs);
pw.println(prefix + "mUpdateTimeMs=" + mUpdateTimeMs);
pw.println(prefix + "mSuppressedVisualEffects= " + mSuppressedVisualEffects);
- if (mPreChannelsNotification) {
+ if (!mSupportsChannels) {
pw.println(prefix + String.format("defaults=0x%08x flags=0x%08x",
notification.defaults, notification.flags));
pw.println(prefix + "n.sound=" + notification.sound);
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 4d19b52..14d796f 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -42,4 +42,6 @@
void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId);
void permanentlyDeleteNotificationChannels(String pkg, int uid);
ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid, boolean includeDeleted);
+
+ boolean supportsChannels(String pkg, int uid);
}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 6d18c83..3481556 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -273,31 +273,21 @@
}
private boolean shouldHaveDefaultChannel(Record r) throws NameNotFoundException {
+ if (supportsChannels(r)) {
+ return false;
+ }
+
final int userId = UserHandle.getUserId(r.uid);
- final ApplicationInfo applicationInfo = mPm.getApplicationInfoAsUser(r.pkg, 0, userId);
- if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
- // Pre-O apps should have it.
- return true;
+ final ApplicationInfo applicationInfo = mPm.getApplicationInfoAsUser(r.pkg,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ userId);
+ if (applicationInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1) {
+ // O apps should not have the default channel.
+ return false;
}
- // STOPSHIP TODO: remove before release - O+ apps should never have a default channel.
- // But for now, leave the default channel until an app has created its first channel.
- boolean hasCreatedAChannel = false;
- final int size = r.channels.size();
- for (int i = 0; i < size; i++) {
- final NotificationChannel notificationChannel = r.channels.valueAt(i);
- if (notificationChannel != null &&
- !notificationChannel.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
- hasCreatedAChannel = true;
- break;
- }
- }
- if (!hasCreatedAChannel) {
- return true;
- }
-
- // Otherwise, should not have the default channel.
- return false;
+ // Otherwise, this app should have the default channel.
+ return true;
}
private void deleteDefaultChannelIfNeeded(Record r) throws NameNotFoundException {
@@ -516,6 +506,31 @@
}
@Override
+ public boolean supportsChannels(String pkg, int uid) {
+ Record r = getOrCreateRecord(pkg, uid);
+
+ if (r == null) {
+ return false;
+ }
+
+ if (r.channels.size() == 1
+ && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean supportsChannels(Record r) {
+ if (r.channels.size() == 1
+ && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
+ return false;
+ }
+
+ return (r.channels.size() > 0);
+ }
+
+ @Override
public void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
boolean fromTargetApp) {
Preconditions.checkNotNull(pkg);
@@ -587,6 +602,10 @@
r.channels.put(channel.getId(), channel);
MetricsLogger.action(getChannelLog(channel, pkg).setType(
MetricsProto.MetricsEvent.TYPE_OPEN));
+
+ // Remove Default Channel.
+ r.channels.remove(NotificationChannel.DEFAULT_CHANNEL_ID);
+
updateConfig();
}
@@ -683,13 +702,7 @@
if (r == null) {
return;
}
- int N = r.channels.size() - 1;
- for (int i = N; i >= 0; i--) {
- String key = r.channels.keyAt(i);
- if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(key)) {
- r.channels.remove(key);
- }
- }
+ r.channels.clear();
updateConfig();
}
@@ -1041,6 +1054,8 @@
final int uid = uidList[i];
synchronized (mRecords) {
mRecords.remove(recordKey(pkg, uid));
+ // reset to default settings and re-add misc channel for pre-O apps
+ getOrCreateRecord(pkg, uid);
}
mRestoredWithoutUids.remove(pkg);
updated = true;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 91a163a..42eebe1 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -184,6 +184,7 @@
import android.service.dreams.DreamManagerInternal;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
+import android.service.vr.IPersistentVrStateCallbacks;
import android.speech.RecognizerIntent;
import android.telecom.TelecomManager;
import android.util.DisplayMetrics;
@@ -512,6 +513,8 @@
volatile boolean mGoingToSleep;
volatile boolean mRecentsVisible;
volatile boolean mPictureInPictureVisible;
+ // Written by vr manager thread, only read in this class.
+ volatile private boolean mPersistentVrModeEnabled;
volatile private boolean mDismissImeOnBackKeyPressed;
// Used to hold the last user key used to wake the device. This helps us prevent up events
@@ -1002,6 +1005,14 @@
}
MyOrientationListener mOrientationListener;
+ final IPersistentVrStateCallbacks mPersistentVrModeListener =
+ new IPersistentVrStateCallbacks.Stub() {
+ @Override
+ public void onPersistentVrStateChanged(boolean enabled) {
+ mPersistentVrModeEnabled = enabled;
+ }
+ };
+
private final StatusBarController mStatusBarController = new StatusBarController();
private final BarController mNavigationBarController = new BarController("NavigationBar",
@@ -6909,7 +6920,13 @@
|| mAllowAllRotations == 1
|| orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
|| orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
- preferredRotation = sensorRotation;
+ // In VrMode, we report the sensor as always being in default orientation so:
+ // 1) The orientation doesn't change as the user moves their head.
+ // 2) 2D apps within VR show in the device's default orientation.
+ // This only overwrites the sensor-provided orientation and does not affect any
+ // explicit orientation preferences specified by any activities.
+ preferredRotation =
+ mPersistentVrModeEnabled ? Surface.ROTATION_0 : sensorRotation;
} else {
preferredRotation = lastRotation;
}
@@ -7083,6 +7100,9 @@
mKeyguardDelegate.onSystemReady();
mVrManagerInternal = LocalServices.getService(VrManagerInternal.class);
+ if (mVrManagerInternal != null) {
+ mVrManagerInternal.addPersistentVrModeStateListener(mPersistentVrModeListener);
+ }
readCameraLensCoverState();
updateUiMode();
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 8c3d80f..423bc0c 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -4632,12 +4632,6 @@
}
@Override
- public void setButtonBrightnessOverrideFromWindowManager(int screenBrightness) {
- // Do nothing.
- // Button lights are not currently supported in the new implementation.
- }
-
- @Override
public void setDozeOverrideFromDreamManager(int screenState, int screenBrightness) {
switch (screenState) {
case Display.STATE_UNKNOWN:
diff --git a/services/core/java/com/android/server/radio/Tuner.java b/services/core/java/com/android/server/radio/Tuner.java
index 248a139..a06d8c6 100644
--- a/services/core/java/com/android/server/radio/Tuner.java
+++ b/services/core/java/com/android/server/radio/Tuner.java
@@ -31,7 +31,8 @@
*/
private final long mNativeContext;
- private int mRegion;
+ private final Object mLock = new Object();
+ private int mRegion; // TODO(b/36863239): find better solution to manage regions
Tuner(@NonNull ITunerCallback clientCallback, int region) {
mRegion = region;
@@ -44,17 +45,44 @@
super.finalize();
}
- private native long nativeInit(ITunerCallback clientCallback);
+ private native long nativeInit(@NonNull ITunerCallback clientCallback);
private native void nativeFinalize(long nativeContext);
private native void nativeClose(long nativeContext);
+ private native void nativeSetConfiguration(long nativeContext,
+ @NonNull RadioManager.BandConfig config);
+ private native RadioManager.BandConfig nativeGetConfiguration(long nativeContext, int region);
+
@Override
public void close() {
- nativeClose(mNativeContext);
+ synchronized (mLock) {
+ nativeClose(mNativeContext);
+ }
+ }
+
+ @Override
+ public void setConfiguration(RadioManager.BandConfig config) {
+ if (config == null) {
+ throw new IllegalArgumentException("The argument must not be a null pointer");
+ }
+ synchronized (mLock) {
+ nativeSetConfiguration(mNativeContext, config);
+ mRegion = config.getRegion();
+ }
+ }
+
+ @Override
+ public RadioManager.BandConfig getConfiguration() {
+ synchronized (mLock) {
+ return nativeGetConfiguration(mNativeContext, mRegion);
+ }
}
@Override
public int getProgramInformation(RadioManager.ProgramInfo[] infoOut) {
+ if (infoOut == null || infoOut.length != 1) {
+ throw new IllegalArgumentException("The argument must be an array of length 1");
+ }
Slog.d(TAG, "getProgramInformation()");
return RadioManager.STATUS_INVALID_OPERATION;
}
diff --git a/services/core/java/com/android/server/twilight/TwilightState.java b/services/core/java/com/android/server/twilight/TwilightState.java
index a12965d..30a8ccc 100644
--- a/services/core/java/com/android/server/twilight/TwilightState.java
+++ b/services/core/java/com/android/server/twilight/TwilightState.java
@@ -31,7 +31,7 @@
private final long mSunriseTimeMillis;
private final long mSunsetTimeMillis;
- TwilightState(long sunriseTimeMillis, long sunsetTimeMillis) {
+ public TwilightState(long sunriseTimeMillis, long sunsetTimeMillis) {
mSunriseTimeMillis = sunriseTimeMillis;
mSunsetTimeMillis = sunsetTimeMillis;
}
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index c625cbe..b5e194b 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -36,7 +36,6 @@
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
import android.os.Trace;
import android.util.Slog;
import android.view.IApplicationToken;
@@ -319,7 +318,7 @@
+ " token: " + mToken);
return;
}
- mContainer.setDisablePreviewSnapshots(disable);
+ mContainer.setDisablePreviewScreenshots(disable);
}
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 36418be..640bac2 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -23,6 +23,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
@@ -48,6 +49,7 @@
import static com.android.server.wm.WindowManagerService.logWithStack;
import android.annotation.NonNull;
+import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
@@ -1528,12 +1530,24 @@
return candidate;
}
- void setDisablePreviewSnapshots(boolean disable) {
+ /**
+ * See {@link Activity#setDisablePreviewScreenshots}.
+ */
+ void setDisablePreviewScreenshots(boolean disable) {
mDisbalePreviewScreenshots = disable;
}
- boolean shouldDisablePreviewScreenshots() {
- return mDisbalePreviewScreenshots;
+ /**
+ * Retrieves whether we'd like to generate a snapshot that's based solely on the theme. This is
+ * the case when preview screenshots are disabled {@link #setDisablePreviewScreenshots} or when
+ * we can't take a snapshot for other reasons, for example, if we have a secure window.
+ *
+ * @return True if we need to generate an app theme snapshot, false if we'd like to take a real
+ * screenshot.
+ */
+ boolean shouldUseAppThemeSnapshot() {
+ return mDisbalePreviewScreenshots || forAllWindows(w -> (w.mAttrs.flags & FLAG_SECURE) != 0,
+ true /* topToBottom */);
}
@Override
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index 4100446..d44cd13 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -188,6 +188,7 @@
boolean animateDimLayers() {
int fullScreen = -1;
int fullScreenAndDimming = -1;
+ int topFullScreenUserLayer = 0;
boolean result = false;
for (int i = mState.size() - 1; i >= 0; i--) {
@@ -213,8 +214,18 @@
// and we have to make sure we always animate the layer.
if (user.dimFullscreen() && state.dimLayer == mSharedFullScreenDimLayer) {
fullScreen = i;
- if (mState.valueAt(i).continueDimming) {
+ if (!state.continueDimming) {
+ continue;
+ }
+
+ // When choosing which user to assign the shared fullscreen layer to
+ // we need to look at Z-order.
+ if (topFullScreenUserLayer == 0 ||
+ (state.animator != null && state.animator.mAnimLayer > topFullScreenUserLayer)) {
fullScreenAndDimming = i;
+ if (state.animator != null) {
+ topFullScreenUserLayer = state.animator.mAnimLayer;
+ }
}
} else {
// We always want to animate the non fullscreen windows, they don't share their
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 67704e7..be242b6 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1503,8 +1503,16 @@
return mImeWindowsContainers.forAllWindows(callback, traverseTopToBottom);
}
- @Override
- int getOrientation() {
+ /**
+ * Returns the orientation that this display should be in factoring in its children containers.
+ *
+ * @param includeAppContainers True if then app containers (stacks, tasks, ...) should be
+ * factored in when determining the orientation. If false only
+ * non-app/system containers will be used to determine the returned
+ * orientation.
+ * @return The orientation the display should be in.
+ */
+ int getOrientation(boolean includeAppContainers) {
final WindowManagerPolicy policy = mService.mPolicy;
if (mService.mDisplayFrozen) {
@@ -1533,8 +1541,14 @@
}
}
- // Top system windows are not requesting an orientation. Start searching from apps.
- return mTaskStackContainers.getOrientation();
+ // Top system windows are not requesting an orientation. Get orientation from app containers
+ // if allowed. Otherwise, return the last orientation.
+ return includeAppContainers ? mTaskStackContainers.getOrientation() : mLastOrientation;
+ }
+
+ @Override
+ int getOrientation() {
+ return getOrientation(true /* includeAppContainers */);
}
void updateDisplayInfo() {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 60b136f..be3558b 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -21,7 +21,10 @@
import android.hardware.power.V1_0.PowerHint;
import android.os.Binder;
import android.os.Debug;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -34,6 +37,8 @@
import android.view.Display;
import android.view.DisplayInfo;
import android.view.WindowManager;
+
+import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.server.EventLogTags;
@@ -87,13 +92,15 @@
class RootWindowContainer extends WindowContainer<DisplayContent> {
private static final String TAG = TAG_WITH_CLASS_NAME ? "RootWindowContainer" : TAG_WM;
+ private static final int SET_SCREEN_BRIGHTNESS_OVERRIDE = 1;
+ private static final int SET_USER_ACTIVITY_TIMEOUT = 2;
+
WindowManagerService mService;
private boolean mWallpaperForceHidingChanged = false;
private Object mLastWindowFreezeSource = null;
private Session mHoldScreen = null;
private float mScreenBrightness = -1;
- private float mButtonBrightness = -1;
private long mUserActivityTimeout = -1;
private boolean mUpdateRotation = false;
// Following variables are for debugging screen wakelock only.
@@ -128,6 +135,8 @@
private final WindowLayersController mLayersController;
final WallpaperController mWallpaperController;
+ private final Handler mHandler;
+
private String mCloseSystemDialogsReason;
private final Consumer<WindowState> mCloseSystemDialogsConsumer = w -> {
if (w.mHasSurface) {
@@ -147,6 +156,7 @@
RootWindowContainer(WindowManagerService service) {
mService = service;
+ mHandler = new MyHandler(service.mH.getLooper());
mLayersController = new WindowLayersController(mService);
mWallpaperController = new WallpaperController(mService);
}
@@ -552,7 +562,6 @@
mHoldScreen = null;
mScreenBrightness = -1;
- mButtonBrightness = -1;
mUserActivityTimeout = -1;
mObscureApplicationContentOnSecondaryDisplays = false;
mSustainedPerformanceModeCurrent = false;
@@ -702,20 +711,13 @@
mService.setHoldScreenLocked(mHoldScreen);
if (!mService.mDisplayFrozen) {
- if (mScreenBrightness < 0 || mScreenBrightness > 1.0f) {
- mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(-1);
- } else {
- mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
- toBrightnessOverride(mScreenBrightness));
- }
- if (mButtonBrightness < 0 || mButtonBrightness > 1.0f) {
- mService.mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(-1);
- } else {
- mService.mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(
- toBrightnessOverride(mButtonBrightness));
- }
- mService.mPowerManagerInternal.setUserActivityTimeoutOverrideFromWindowManager(
- mUserActivityTimeout);
+ final int brightness = mScreenBrightness < 0 || mScreenBrightness > 1.0f
+ ? -1 : toBrightnessOverride(mScreenBrightness);
+
+ // Post these on a handler such that we don't call into power manager service while
+ // holding the window manager lock to avoid lock contention with power manager lock.
+ mHandler.obtainMessage(SET_SCREEN_BRIGHTNESS_OVERRIDE, brightness, 0).sendToTarget();
+ mHandler.obtainMessage(SET_USER_ACTIVITY_TIMEOUT, mUserActivityTimeout).sendToTarget();
}
if (mSustainedPerformanceModeCurrent != mSustainedPerformanceModeEnabled) {
@@ -863,9 +865,6 @@
if (!syswin && w.mAttrs.screenBrightness >= 0 && mScreenBrightness < 0) {
mScreenBrightness = w.mAttrs.screenBrightness;
}
- if (!syswin && w.mAttrs.buttonBrightness >= 0 && mButtonBrightness < 0) {
- mButtonBrightness = w.mAttrs.buttonBrightness;
- }
if (!syswin && w.mAttrs.userActivityTimeout >= 0 && mUserActivityTimeout < 0) {
mUserActivityTimeout = w.mAttrs.userActivityTimeout;
}
@@ -935,6 +934,29 @@
return (int)(value * PowerManager.BRIGHTNESS_ON);
}
+ private final class MyHandler extends Handler {
+
+ public MyHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case SET_SCREEN_BRIGHTNESS_OVERRIDE:
+ mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
+ msg.arg1);
+ break;
+ case SET_USER_ACTIVITY_TIMEOUT:
+ mService.mPowerManagerInternal.setUserActivityTimeoutOverrideFromWindowManager(
+ (Long) msg.obj);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
void enableSurfaceTrace(ParcelFileDescriptor pfd) {
final FileDescriptor fd = pfd.getFileDescriptor();
if (mSurfaceTraceEnabled) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index fbb826d..b79173c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -31,11 +31,13 @@
import android.graphics.Rect;
import android.os.Environment;
import android.util.ArraySet;
+import android.view.WindowManager.LayoutParams;
import android.view.WindowManagerPolicy.StartingSurface;
import com.google.android.collect.Sets;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.wm.TaskSnapshotSurface.SystemBarBackgroundPainter;
import java.io.PrintWriter;
@@ -206,7 +208,7 @@
final AppWindowToken topChild = task.getTopChild();
if (StackId.isHomeOrRecentsStack(task.mStack.mStackId)) {
return SNAPSHOT_MODE_NONE;
- } else if (topChild != null && topChild.shouldDisablePreviewScreenshots()) {
+ } else if (topChild != null && topChild.shouldUseAppThemeSnapshot()) {
return SNAPSHOT_MODE_APP_THEME;
} else {
return SNAPSHOT_MODE_REAL;
@@ -227,6 +229,8 @@
return null;
}
final int color = task.getTaskDescription().getBackgroundColor();
+ final int statusBarColor = task.getTaskDescription().getStatusBarColor();
+ final int navigationBarColor = task.getTaskDescription().getNavigationBarColor();
final GraphicBuffer buffer = GraphicBuffer.create(mainWindow.getFrameLw().width(),
mainWindow.getFrameLw().height(),
RGBA_8888, USAGE_HW_TEXTURE | USAGE_SW_WRITE_RARELY | USAGE_SW_READ_NEVER);
@@ -235,6 +239,11 @@
}
final Canvas c = buffer.lockCanvas();
c.drawColor(color);
+ final LayoutParams attrs = mainWindow.getAttrs();
+ final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
+ attrs.privateFlags, attrs.systemUiVisibility, statusBarColor, navigationBarColor);
+ decorPainter.setInsets(mainWindow.mContentInsets, mainWindow.mStableInsets);
+ decorPainter.drawDecors(c, null /* statusBarExcludeFrame */);
buffer.unlockCanvasAndPost(c);
return new TaskSnapshot(buffer, topChild.getConfiguration().orientation,
mainWindow.mStableInsets, false /* reduced */, 1.0f /* scale */);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index c816ba3..2b9e800 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -42,8 +42,11 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.annotation.Nullable;
import android.app.ActivityManager.TaskDescription;
import android.app.ActivityManager.TaskSnapshot;
+import android.app.ActivityThread;
+import android.content.Context;
import android.graphics.Canvas;
import android.graphics.GraphicBuffer;
import android.graphics.Paint;
@@ -118,13 +121,8 @@
private final Handler mHandler;
private boolean mSizeMismatch;
private final Paint mBackgroundPaint = new Paint();
- private final Paint mStatusBarPaint = new Paint();
- private final Paint mNavigationBarPaint = new Paint();
private final int mStatusBarColor;
- private final int mNavigationBarColor;
- private final int mSysUiVis;
- private final int mWindowFlags;
- private final int mWindowPrivateFlags;
+ @VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
TaskSnapshot snapshot) {
@@ -224,15 +222,9 @@
mTitle = title;
mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
mTaskBounds = taskBounds;
- mSysUiVis = sysUiVis;
- mWindowFlags = windowFlags;
- mWindowPrivateFlags = windowPrivateFlags;
- mStatusBarColor = DecorView.calculateStatusBarColor(windowFlags,
- service.mContext.getColor(R.color.system_bar_background_semi_transparent),
- statusBarColor);
- mNavigationBarColor = navigationBarColor;
- mStatusBarPaint.setColor(mStatusBarColor);
- mNavigationBarPaint.setColor(navigationBarColor);
+ mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
+ windowPrivateFlags, sysUiVis, statusBarColor, navigationBarColor);
+ mStatusBarColor = statusBarColor;
}
@Override
@@ -258,6 +250,7 @@
mStableInsets.set(stableInsets);
mSizeMismatch = (mFrame.width() != mSnapshot.getSnapshot().getWidth()
|| mFrame.height() != mSnapshot.getSnapshot().getHeight());
+ mSystemBarBackgroundPainter.setInsets(contentInsets, stableInsets);
}
private void drawSnapshot() {
@@ -346,7 +339,7 @@
@VisibleForTesting
void drawBackgroundAndBars(Canvas c, Rect frame) {
- final int statusBarHeight = getStatusBarColorViewHeight();
+ final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight();
final boolean fillHorizontally = c.getWidth() > frame.right;
final boolean fillVertically = c.getHeight() > frame.bottom;
if (fillHorizontally) {
@@ -359,44 +352,7 @@
if (fillVertically) {
c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint);
}
- drawStatusBarBackground(c, frame, statusBarHeight);
- drawNavigationBarBackground(c);
- }
-
- private int getStatusBarColorViewHeight() {
- final boolean forceStatusBarBackground =
- (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
- if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
- mSysUiVis, mStatusBarColor, mWindowFlags, forceStatusBarBackground)) {
- return getColorViewTopInset(mStableInsets.top, mContentInsets.top);
- } else {
- return 0;
- }
- }
-
- private boolean isNavigationBarColorViewVisible() {
- return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
- mSysUiVis, mNavigationBarColor, mWindowFlags, false /* force */);
- }
-
- @VisibleForTesting
- void drawStatusBarBackground(Canvas c, Rect frame, int statusBarHeight) {
- if (statusBarHeight > 0 && c.getWidth() > frame.right) {
- final int rightInset = DecorView.getColorViewRightInset(mStableInsets.right,
- mContentInsets.right);
- c.drawRect(frame.right, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
- }
- }
-
- @VisibleForTesting
- void drawNavigationBarBackground(Canvas c) {
- final Rect navigationBarRect = new Rect();
- getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets,
- navigationBarRect);
- final boolean visible = isNavigationBarColorViewVisible();
- if (visible && !navigationBarRect.isEmpty()) {
- c.drawRect(navigationBarRect, mNavigationBarPaint);
- }
+ mSystemBarBackgroundPainter.drawDecors(c, frame);
}
private void reportDrawn() {
@@ -450,4 +406,84 @@
}
}
}
+
+ /**
+ * Helper class to draw the background of the system bars in regions the task snapshot isn't
+ * filling the window.
+ */
+ static class SystemBarBackgroundPainter {
+
+ private final Rect mContentInsets = new Rect();
+ private final Rect mStableInsets = new Rect();
+ private final Paint mStatusBarPaint = new Paint();
+ private final Paint mNavigationBarPaint = new Paint();
+ private final int mStatusBarColor;
+ private final int mNavigationBarColor;
+ private final int mWindowFlags;
+ private final int mWindowPrivateFlags;
+ private final int mSysUiVis;
+
+ SystemBarBackgroundPainter( int windowFlags, int windowPrivateFlags, int sysUiVis,
+ int statusBarColor, int navigationBarColor) {
+ mWindowFlags = windowFlags;
+ mWindowPrivateFlags = windowPrivateFlags;
+ mSysUiVis = sysUiVis;
+ final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
+ mStatusBarColor = DecorView.calculateStatusBarColor(windowFlags,
+ context.getColor(R.color.system_bar_background_semi_transparent),
+ statusBarColor);
+ mNavigationBarColor = navigationBarColor;
+ mStatusBarPaint.setColor(mStatusBarColor);
+ mNavigationBarPaint.setColor(navigationBarColor);
+ }
+
+ void setInsets(Rect contentInsets, Rect stableInsets) {
+ mContentInsets.set(contentInsets);
+ mStableInsets.set(stableInsets);
+ }
+
+ int getStatusBarColorViewHeight() {
+ final boolean forceStatusBarBackground =
+ (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
+ if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+ mSysUiVis, mStatusBarColor, mWindowFlags, forceStatusBarBackground)) {
+ return getColorViewTopInset(mStableInsets.top, mContentInsets.top);
+ } else {
+ return 0;
+ }
+ }
+
+ private boolean isNavigationBarColorViewVisible() {
+ return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+ mSysUiVis, mNavigationBarColor, mWindowFlags, false /* force */);
+ }
+
+ void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
+ drawStatusBarBackground(c, alreadyDrawnFrame, getStatusBarColorViewHeight());
+ drawNavigationBarBackground(c);
+ }
+
+ @VisibleForTesting
+ void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
+ int statusBarHeight) {
+ if (statusBarHeight > 0
+ && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
+ final int rightInset = DecorView.getColorViewRightInset(mStableInsets.right,
+ mContentInsets.right);
+ final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
+ c.drawRect(left, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
+ }
+ }
+
+ @VisibleForTesting
+ void drawNavigationBarBackground(Canvas c) {
+ final Rect navigationBarRect = new Rect();
+ getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets,
+ navigationBarRect);
+ final boolean visible = isNavigationBarColorViewVisible();
+ if (visible && !navigationBarRect.isEmpty()) {
+ c.drawRect(navigationBarRect, mNavigationBarPaint);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a7f6600..a48397b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2373,7 +2373,7 @@
try {
synchronized(mWindowMap) {
config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded,
- displayId);
+ displayId, true /* includeAppContainers */);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -2383,13 +2383,13 @@
}
private Configuration updateOrientationFromAppTokensLocked(Configuration currentConfig,
- IBinder freezeThisOneIfNeeded, int displayId) {
+ IBinder freezeThisOneIfNeeded, int displayId, boolean includeAppContainers) {
if (!mDisplayReady) {
return null;
}
Configuration config = null;
- if (updateOrientationFromAppTokensLocked(false, displayId)) {
+ if (updateOrientationFromAppTokensLocked(false, displayId, includeAppContainers)) {
// If we changed the orientation but mOrientationChangeComplete is already true,
// we used seamless rotation, and we don't need to freeze the screen.
if (freezeThisOneIfNeeded != null && !mRoot.mOrientationChangeComplete) {
@@ -2427,6 +2427,11 @@
return config;
}
+ boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId) {
+ return updateOrientationFromAppTokensLocked(inTransaction, displayId,
+ false /* includeAppContainers */);
+ }
+
/**
* Determine the new desired orientation of the display, returning a non-null new Configuration
* if it has changed from the current orientation. IF TRUE IS RETURNED SOMEONE MUST CALL
@@ -2437,13 +2442,25 @@
* The orientation is computed from non-application windows first. If none of the
* non-application windows specify orientation, the orientation is computed from application
* tokens.
+ *
+ * @param inTransaction True if we are currently in a surface transaction.
+ * @param displayId Id of the display to update orientation for.
+ * @param includeAppContainers True if then app containers (stacks, tasks, ...) should be
+ * factored in when determining the orientation. If false only
+ * non-app/system containers will be used to determine the returned
+ * orientation.
+ * NOTE: Only call originating from activity manager are expected to
+ * set this to true as it needs to synchronize several app states
+ * like visibility with the update of display orientation.
+ * @return True if the display orientation was updated.
* @see android.view.IWindowManager#updateOrientationFromAppTokens(Configuration, IBinder, int)
*/
- boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId) {
- long ident = Binder.clearCallingIdentity();
+ private boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId,
+ boolean includeAppContainers) {
+ final long ident = Binder.clearCallingIdentity();
try {
final DisplayContent dc = mRoot.getDisplayContent(displayId);
- final int req = dc.getOrientation();
+ final int req = dc.getOrientation(includeAppContainers);
if (req != dc.getLastOrientation()) {
dc.setLastOrientation(req);
//send a message to Policy indicating orientation change to take
diff --git a/services/core/jni/com_android_server_radio_Tuner.cpp b/services/core/jni/com_android_server_radio_Tuner.cpp
index 3245bff..96e122d 100644
--- a/services/core/jni/com_android_server_radio_Tuner.cpp
+++ b/services/core/jni/com_android_server_radio_Tuner.cpp
@@ -19,6 +19,7 @@
#include "com_android_server_radio_Tuner.h"
+#include "com_android_server_radio_convert.h"
#include "com_android_server_radio_Tuner_TunerCallback.h"
#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
@@ -104,6 +105,13 @@
ctx.mHalTuner = halTuner;
}
+sp<ITuner> getHalTuner(jlong nativeContext) {
+ AutoMutex _l(gContextMutex);
+ auto tuner = getNativeContext(nativeContext).mHalTuner;
+ LOG_ALWAYS_FATAL_IF(tuner == nullptr, "HAL tuner not set");
+ return tuner;
+}
+
sp<ITunerCallback> getNativeCallback(JNIEnv *env, jobject obj) {
AutoMutex _l(gContextMutex);
auto& ctx = getNativeContext(env, obj);
@@ -114,7 +122,7 @@
return static_cast<Region>(env->GetIntField(obj, gjni.Tuner.region));
}
-static void close(JNIEnv *env, jobject obj, jlong nativeContext) {
+static void nativeClose(JNIEnv *env, jobject obj, jlong nativeContext) {
AutoMutex _l(gContextMutex);
auto& ctx = getNativeContext(nativeContext);
ALOGI("Closing tuner %p", ctx.mHalTuner.get());
@@ -123,10 +131,42 @@
ctx.mNativeCallback = nullptr;
}
+static void nativeSetConfiguration(JNIEnv *env, jobject obj, jlong nativeContext, jobject config) {
+ ALOGV("nativeSetConfiguration()");
+ auto halTuner = getHalTuner(nativeContext);
+
+ Region region_unused;
+ BandConfig bandConfigHal = convert::BandConfigToHal(env, config, region_unused);
+
+ convert::ThrowIfFailed(env, halTuner->setConfiguration(bandConfigHal));
+}
+
+static jobject nativeGetConfiguration(JNIEnv *env, jobject obj, jlong nativeContext,
+ Region region) {
+ ALOGV("nativeSetConfiguration()");
+ auto halTuner = getHalTuner(nativeContext);
+
+ BandConfig halConfig;
+ Result halResult;
+ auto hidlResult = halTuner->getConfiguration([&](Result result, const BandConfig& config) {
+ halResult = result;
+ halConfig = config;
+ });
+ if (convert::ThrowIfFailed(env, hidlResult)) {
+ return nullptr;
+ }
+
+ return convert::BandConfigFromHal(env, halConfig, region).release();
+}
+
static const JNINativeMethod gTunerMethods[] = {
{ "nativeInit", "(Landroid/hardware/radio/ITunerCallback;)J", (void*)nativeInit },
{ "nativeFinalize", "(J)V", (void*)nativeFinalize },
- { "nativeClose", "(J)V", (void*)close },
+ { "nativeClose", "(J)V", (void*)nativeClose },
+ { "nativeSetConfiguration", "(JLandroid/hardware/radio/RadioManager$BandConfig;)V",
+ (void*)nativeSetConfiguration },
+ { "nativeGetConfiguration", "(JI)Landroid/hardware/radio/RadioManager$BandConfig;",
+ (void*)nativeGetConfiguration },
};
} // namespace Tuner
diff --git a/services/core/jni/com_android_server_radio_convert.cpp b/services/core/jni/com_android_server_radio_convert.cpp
index afa3539..419e6d6 100644
--- a/services/core/jni/com_android_server_radio_convert.cpp
+++ b/services/core/jni/com_android_server_radio_convert.cpp
@@ -28,10 +28,12 @@
namespace radio {
namespace convert {
+using hardware::Return;
using hardware::hidl_vec;
using V1_0::Band;
using V1_0::Deemphasis;
+using V1_0::Result;
using V1_0::Rds;
static struct {
@@ -62,6 +64,47 @@
} BandDescriptor;
} gjni;
+template <typename T>
+bool ThrowIfFailedCommon(JNIEnv *env, const hardware::Return<T> &hidlResult) {
+ if (hidlResult.isOk()) return false;
+
+ jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+ "HIDL call failed: %s", hidlResult.description().c_str());
+ return true;
+}
+
+bool ThrowIfFailed(JNIEnv *env, const hardware::Return<void> &hidlResult) {
+ return ThrowIfFailedCommon(env, hidlResult);
+}
+
+bool ThrowIfFailed(JNIEnv *env, const hardware::Return<V1_0::Result> &hidlResult) {
+ if (ThrowIfFailedCommon(env, hidlResult)) return true;
+
+ Result result = hidlResult;
+ switch (result) {
+ case Result::OK:
+ return false;
+ case Result::NOT_INITIALIZED:
+ jniThrowException(env, "java/lang/RuntimeException", "Result::NOT_INITIALIZED");
+ return true;
+ case Result::INVALID_ARGUMENTS:
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Result::INVALID_ARGUMENTS");
+ return true;
+ case Result::INVALID_STATE:
+ jniThrowException(env, "java/lang/IllegalStateException", "Result::INVALID_STATE");
+ return true;
+ case Result::TIMEOUT:
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Result::TIMEOUT (unexpected here)");
+ return true;
+ default:
+ jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+ "Unknown failure, result: %d", result);
+ return true;
+ }
+}
+
static Rds RdsForRegion(bool rds, Region region) {
if (!rds) return Rds::NONE;
@@ -95,6 +138,7 @@
}
JavaRef BandConfigFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region) {
+ ALOGV("BandConfigFromHal()");
EnvWrapper wrap(env);
jint spacing = config.spacings.size() > 0 ? config.spacings[0] : 0;
@@ -122,6 +166,7 @@
}
V1_0::BandConfig BandConfigToHal(JNIEnv *env, jobject jConfig, Region ®ion) {
+ ALOGV("BandConfigToHal()");
auto jDescriptor = env->GetObjectField(jConfig, gjni.BandConfig.descriptor);
if (jDescriptor == nullptr) {
ALOGE("Descriptor is missing");
diff --git a/services/core/jni/com_android_server_radio_convert.h b/services/core/jni/com_android_server_radio_convert.h
index b7e5b9c..dba948e 100644
--- a/services/core/jni/com_android_server_radio_convert.h
+++ b/services/core/jni/com_android_server_radio_convert.h
@@ -37,6 +37,9 @@
JavaRef BandConfigFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region);
V1_0::BandConfig BandConfigToHal(JNIEnv *env, jobject jConfig, Region ®ion);
+bool ThrowIfFailed(JNIEnv *env, const hardware::Return<V1_0::Result> &hidlResult);
+bool ThrowIfFailed(JNIEnv *env, const hardware::Return<void> &hidlResult);
+
} // namespace convert
} // namespace radio
} // namespace server
diff --git a/services/core/jni/com_android_server_radio_types.h b/services/core/jni/com_android_server_radio_types.h
index f2f253c..8430e05 100644
--- a/services/core/jni/com_android_server_radio_types.h
+++ b/services/core/jni/com_android_server_radio_types.h
@@ -27,6 +27,18 @@
* frameworks/base/core/java/android/hardware/radio/RadioManager.java.
*/
+// Keep in sync with STATUS_* constants from RadioManager.java.
+enum class Status : jint {
+ OK = 0,
+ ERROR = -0x80000000ll, // Integer.MIN_VALUE
+ PERMISSION_DENIED = -1, // -EPERM
+ NO_INIT = -19, // -ENODEV
+ BAD_VALUE = -22, // -EINVAL
+ DEAD_OBJECT = -32, // -EPIPE
+ INVALID_OPERATION = -38, // -ENOSYS
+ TIMED_OUT = -110, // -ETIMEDOUT
+};
+
// Keep in sync with REGION_* constants from RadioManager.java.
enum class Region : jint {
ITU_1 = 0,
diff --git a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
index 0cf4994..2e8b068 100644
--- a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
@@ -69,7 +69,7 @@
Notification n = builder.build();
StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
mPid, n, mUser, null, System.currentTimeMillis());
- NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+ NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
return r;
}
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index d4904f5..5e8b3d4 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -259,7 +259,7 @@
StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid,
mPid, n, mUser, null, System.currentTimeMillis());
- NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+ NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
mService.addNotification(r);
return r;
}
@@ -769,7 +769,7 @@
StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
mPid, n, mUser, null, System.currentTimeMillis());
- NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+ NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
mService.addNotification(r);
mService.buzzBeepBlinkLocked(r);
diff --git a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
index 24cb72e..33d2d07 100644
--- a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
@@ -53,21 +53,21 @@
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
- "", 1499), getDefaultChannel());
+ "", 1499), getDefaultChannel(), true);
left.setGlobalSortKey("first");
NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
- "", 1499), getDefaultChannel());
+ "", 1499), getDefaultChannel(), true);
right.setGlobalSortKey("second");
NotificationRecord last = new NotificationRecord(InstrumentationRegistry.getContext(),
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
- "", 1499), getDefaultChannel());
+ "", 1499), getDefaultChannel(), true);
final List<NotificationRecord> expected = new ArrayList<>();
@@ -93,13 +93,13 @@
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
- "", 1499), getDefaultChannel());
+ "", 1499), getDefaultChannel(), true);
NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
- "", 1499), getDefaultChannel());
+ "", 1499), getDefaultChannel(), true);
right.setGlobalSortKey("not null");
final List<NotificationRecord> expected = new ArrayList<>();
@@ -124,14 +124,14 @@
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
- "", 1499), getDefaultChannel());
+ "", 1499), getDefaultChannel(), true);
left.setGlobalSortKey("not null");
NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
- "", 1499), getDefaultChannel());
+ "", 1499), getDefaultChannel(), true);
final List<NotificationRecord> expected = new ArrayList<>();
expected.add(left);
diff --git a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
index 3dbd803..7a2dbaf 100644
--- a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
@@ -71,7 +71,7 @@
Notification n = builder.build();
StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
mPid, n, mUser, null, System.currentTimeMillis());
- NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+ NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
return r;
}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
index 84945ab..ccd2db0 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
@@ -108,7 +108,7 @@
.build();
mRecordMinCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
callPkg, 1, "minCall", callUid, callUid, n1,
- new UserHandle(userId), "", 2000), getDefaultChannel());
+ new UserHandle(userId), "", 2000), getDefaultChannel(), false);
mRecordMinCall.setUserImportance(NotificationManager.IMPORTANCE_MIN);
Notification n2 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -118,7 +118,7 @@
.build();
mRecordHighCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
callPkg, 1, "highcall", callUid, callUid, n2,
- new UserHandle(userId), "", 1999), getDefaultChannel());
+ new UserHandle(userId), "", 1999), getDefaultChannel(), false);
mRecordHighCall.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
Notification n3 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -128,14 +128,14 @@
.build();
mRecordDefaultMedia = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "media", uid2, uid2, n3, new UserHandle(userId),
- "", 1499), getDefaultChannel());
+ "", 1499), getDefaultChannel(), false);
mRecordDefaultMedia.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
Notification n4 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setStyle(new Notification.MessagingStyle("sender!")).build();
mRecordInlineReply = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "inlinereply", uid2, uid2, n4, new UserHandle(userId),
- "", 1599), getDefaultChannel());
+ "", 1599), getDefaultChannel(), false);
mRecordInlineReply.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
mRecordInlineReply.setPackagePriority(Notification.PRIORITY_MAX);
@@ -143,27 +143,27 @@
.setCategory(Notification.CATEGORY_MESSAGE).build();
mRecordSms = new NotificationRecord(mContext, new StatusBarNotification(smsPkg,
smsPkg, 1, "sms", smsUid, smsUid, n5, new UserHandle(userId),
- "", 1299), getDefaultChannel());
+ "", 1299), getDefaultChannel(), false);
mRecordSms.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
Notification n6 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordStarredContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "starred", uid2, uid2, n6, new UserHandle(userId),
- "", 1259), getDefaultChannel());
+ "", 1259), getDefaultChannel(), false);
mRecordStarredContact.setContactAffinity(ValidateNotificationPeople.STARRED_CONTACT);
mRecordStarredContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
Notification n7 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "contact", uid2, uid2, n7, new UserHandle(userId),
- "", 1259), getDefaultChannel());
+ "", 1259), getDefaultChannel(), false);
mRecordContact.setContactAffinity(ValidateNotificationPeople.VALID_CONTACT);
mRecordContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
Notification n8 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordUrgent = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "urgent", uid2, uid2, n8, new UserHandle(userId),
- "", 1258), getDefaultChannel());
+ "", 1258), getDefaultChannel(), false);
mRecordUrgent.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
Notification n9 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -173,7 +173,7 @@
.build();
mRecordCheater = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "cheater", uid2, uid2, n9, new UserHandle(userId),
- "", 9258), getDefaultChannel());
+ "", 9258), getDefaultChannel(), false);
mRecordCheater.setUserImportance(NotificationManager.IMPORTANCE_LOW);
mRecordCheater.setPackagePriority(Notification.PRIORITY_MAX);
@@ -181,7 +181,7 @@
.setStyle(new Notification.InboxStyle().setSummaryText("message!")).build();
mRecordEmail = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "email", uid2, uid2, n10, new UserHandle(userId),
- "", 1599), getDefaultChannel());
+ "", 1599), getDefaultChannel(), false);
mRecordEmail.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
Notification n11 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -190,7 +190,7 @@
.build();
mRecordCheaterColorized = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "cheater", uid2, uid2, n11, new UserHandle(userId),
- "", 9258), getDefaultChannel());
+ "", 9258), getDefaultChannel(), false);
mRecordCheaterColorized.setUserImportance(NotificationManager.IMPORTANCE_LOW);
}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 177c02d..f3eb4f8 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -165,7 +165,7 @@
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", uid, 0,
nb.build(), new UserHandle(uid), null, 0);
- return new NotificationRecord(mContext, sbn, channel);
+ return new NotificationRecord(mContext, sbn, channel, true);
}
private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
return generateNotificationRecord(channel, null);
@@ -184,7 +184,7 @@
}
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", uid, 0,
nb.build(), new UserHandle(uid), null, 0);
- return new NotificationRecord(mContext, sbn, channel);
+ return new NotificationRecord(mContext, sbn, channel, true);
}
@Test
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
index 1c8ca84..66f3799 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
@@ -21,7 +21,6 @@
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
-import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
@@ -61,6 +60,10 @@
private final Context mMockContext = Mockito.mock(Context.class);
@Mock PackageManager mPm;
+ // constants for targetSdk version. N is pre channels, O is post.
+ private final boolean N = false;
+ private final boolean O = true;
+
private final String pkg = "com.android.server.notification";
private final int uid = 9583;
private final String pkg2 = "pkg2";
@@ -76,7 +79,6 @@
new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "test",
NotificationManager.IMPORTANCE_UNSPECIFIED);
private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
- final ApplicationInfo legacy = new ApplicationInfo();
final ApplicationInfo upgrade = new ApplicationInfo();
private static final long[] CUSTOM_VIBRATION = new long[] {
@@ -100,17 +102,13 @@
InstrumentationRegistry.getContext().getResources());
when(mMockContext.getPackageManager()).thenReturn(mPm);
- legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
upgrade.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
- try {
- when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(legacy);
- when(mPm.getApplicationInfoAsUser(eq(pkg2), anyInt(), anyInt())).thenReturn(upgrade);
- } catch (PackageManager.NameNotFoundException e) {}
+ when(mMockContext.getApplicationInfo()).thenReturn(upgrade);
}
- private StatusBarNotification getNotification(boolean preO, boolean noisy, boolean defaultSound,
- boolean buzzy, boolean defaultVibration, boolean lights, boolean defaultLights) {
- when(mMockContext.getApplicationInfo()).thenReturn(preO ? legacy : upgrade);
+ private StatusBarNotification getNotification(boolean supportsChannels, boolean noisy,
+ boolean defaultSound, boolean buzzy, boolean defaultVibration, boolean lights,
+ boolean defaultLights) {
final Builder builder = new Builder(mMockContext)
.setContentTitle("foo")
.setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -149,13 +147,13 @@
}
builder.setDefaults(defaults);
- if (!preO) {
+ if (supportsChannels) {
builder.setChannelId(channelId);
}
Notification n = builder.build();
- if (preO) {
+ if (!supportsChannels) {
return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n,
mUser, null, uid);
} else {
@@ -172,11 +170,11 @@
public void testSound_default_preUpgradeUsesNotification() throws Exception {
defaultChannel.setSound(null, null);
// pre upgrade, default sound.
- StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+ StatusBarNotification sbn = getNotification(N, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, record.getSound());
assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, record.getAudioAttributes());
}
@@ -185,11 +183,11 @@
public void testSound_custom_preUpgradeUsesNotification() throws Exception {
defaultChannel.setSound(null, null);
// pre upgrade, custom sound.
- StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+ StatusBarNotification sbn = getNotification(N, true /* noisy */,
false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
assertEquals(CUSTOM_SOUND, record.getSound());
assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
}
@@ -199,11 +197,11 @@
defaultChannel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
defaultChannel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
// pre upgrade, default sound.
- StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+ StatusBarNotification sbn = getNotification(N, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
assertEquals(CUSTOM_SOUND, record.getSound());
assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
}
@@ -211,11 +209,11 @@
@Test
public void testSound_noSound_preUpgrade() throws Exception {
// pre upgrade, default sound.
- StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
+ StatusBarNotification sbn = getNotification(N, false /* noisy */,
false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
assertEquals(null, record.getSound());
assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, record.getAudioAttributes());
}
@@ -224,11 +222,11 @@
public void testSound_default_upgradeUsesChannel() throws Exception {
channel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
// post upgrade, default sound.
- StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+ StatusBarNotification sbn = getNotification(O, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
assertEquals(CUSTOM_SOUND, record.getSound());
assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
}
@@ -237,11 +235,11 @@
public void testVibration_default_preUpgradeUsesNotification() throws Exception {
defaultChannel.enableVibration(false);
// pre upgrade, default vibration.
- StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
+ StatusBarNotification sbn = getNotification(N, false /* noisy */,
false /* defaultSound */, true /* buzzy */, true /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
assertNotNull(record.getVibration());
}
@@ -249,11 +247,11 @@
public void testVibration_custom_preUpgradeUsesNotification() throws Exception {
defaultChannel.enableVibration(false);
// pre upgrade, custom vibration.
- StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
+ StatusBarNotification sbn = getNotification(N, false /* noisy */,
false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
assertEquals(CUSTOM_VIBRATION, record.getVibration());
}
@@ -262,11 +260,11 @@
defaultChannel.enableVibration(true);
defaultChannel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
// pre upgrade, custom vibration.
- StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
+ StatusBarNotification sbn = getNotification(N, false /* noisy */,
false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
assertTrue(!Objects.equals(CUSTOM_VIBRATION, record.getVibration()));
}
@@ -274,20 +272,20 @@
public void testVibration_custom_upgradeUsesChannel() throws Exception {
channel.enableVibration(true);
// post upgrade, custom vibration.
- StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
+ StatusBarNotification sbn = getNotification(O, false /* noisy */,
false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
assertEquals(CUSTOM_CHANNEL_VIBRATION, record.getVibration());
}
@Test
public void testImportance_preUpgrade() throws Exception {
- StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+ StatusBarNotification sbn = getNotification(N, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
assertEquals(NotificationManager.IMPORTANCE_HIGH, record.getImportance());
}
@@ -295,11 +293,11 @@
public void testImportance_locked_preUpgrade() throws Exception {
defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
defaultChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
- StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+ StatusBarNotification sbn = getNotification(N, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
assertEquals(NotificationManager.IMPORTANCE_LOW, record.getImportance());
}
@@ -307,39 +305,39 @@
public void testImportance_locked_unspecified_preUpgrade() throws Exception {
defaultChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
defaultChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
- StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+ StatusBarNotification sbn = getNotification(N, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
assertEquals(NotificationManager.IMPORTANCE_HIGH, record.getImportance());
}
@Test
public void testImportance_upgrade() throws Exception {
- StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+ StatusBarNotification sbn = getNotification(O, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
assertEquals(NotificationManager.IMPORTANCE_DEFAULT, record.getImportance());
}
@Test
public void testLights_preUpgrade_noLight() throws Exception {
- StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+ StatusBarNotification sbn = getNotification(N, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
assertNull(record.getLight());
}
@Test
public void testLights_preUpgrade() throws Exception {
- StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+ StatusBarNotification sbn = getNotification(N, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
true /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
assertEquals(CUSTOM_LIGHT, record.getLight());
}
@@ -347,11 +345,11 @@
public void testLights_locked_preUpgrade() throws Exception {
defaultChannel.enableLights(true);
defaultChannel.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
- StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+ StatusBarNotification sbn = getNotification(N, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
true /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
assertFalse(CUSTOM_LIGHT.equals(record.getLight()));
}
@@ -366,10 +364,10 @@
NotificationRecord.Light expected = new NotificationRecord.Light(
defaultLightColor, defaultLightOn, defaultLightOff);
- StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+ StatusBarNotification sbn = getNotification(O, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
true /* lights */, true /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
assertEquals(expected, record.getLight());
}
@@ -382,19 +380,19 @@
NotificationRecord.Light expected = new NotificationRecord.Light(
Color.BLUE, defaultLightOn, defaultLightOff);
- StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+ StatusBarNotification sbn = getNotification(O, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
true /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
assertEquals(expected, record.getLight());
}
@Test
public void testLights_upgrade_noLight() throws Exception {
- StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+ StatusBarNotification sbn = getNotification(O, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /*defaultLights */);
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, O);
assertNull(record.getLight());
}
}
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index ce899e3..e2428b9 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -124,7 +124,7 @@
.build();
mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, mNotiGroupGSortA, user,
- null, System.currentTimeMillis()), getDefaultChannel());
+ null, System.currentTimeMillis()), getDefaultChannel(), false);
mNotiGroupGSortB = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("B")
@@ -134,7 +134,7 @@
.build();
mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, mNotiGroupGSortB, user,
- null, System.currentTimeMillis()), getDefaultChannel());
+ null, System.currentTimeMillis()), getDefaultChannel(), false);
mNotiNoGroup = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("C")
@@ -142,7 +142,7 @@
.build();
mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, mNotiNoGroup, user,
- null, System.currentTimeMillis()), getDefaultChannel());
+ null, System.currentTimeMillis()), getDefaultChannel(), false);
mNotiNoGroup2 = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("D")
@@ -150,7 +150,7 @@
.build();
mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, mNotiNoGroup2, user,
- null, System.currentTimeMillis()), getDefaultChannel());
+ null, System.currentTimeMillis()), getDefaultChannel(), false);
mNotiNoGroupSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("E")
@@ -159,7 +159,7 @@
.build();
mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, mNotiNoGroupSortA, user,
- null, System.currentTimeMillis()), getDefaultChannel());
+ null, System.currentTimeMillis()), getDefaultChannel(), false);
mAudioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
@@ -314,8 +314,6 @@
assertEquals(channel1, mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
compareChannels(channel2,
mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
- assertNotNull(mHelper.getNotificationChannel(
- PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false));
List<NotificationChannelGroup> actualGroups =
mHelper.getNotificationChannelGroups(PKG, UID, false).getList();
@@ -375,18 +373,13 @@
assertNull(mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
assertNull(mHelper.getNotificationChannel(PKG, UID, channel3.getId(), false));
assertNull(mHelper.getNotificationChannelGroup(ncg.getId(), PKG, UID));
- //assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG, UID));
+ assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG, UID));
assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
}
@Test
public void testChannelXml_defaultChannelLegacyApp_noUserSettings() throws Exception {
- NotificationChannel channel1 =
- new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_DEFAULT);
-
- mHelper.createNotificationChannel(PKG, UID, channel1, true);
-
- ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, channel1.getId(),
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
NotificationChannel.DEFAULT_CHANNEL_ID);
loadStreamXml(baos);
@@ -401,16 +394,12 @@
@Test
public void testChannelXml_defaultChannelUpdatedApp_userSettings() throws Exception {
- NotificationChannel channel1 =
- new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_MIN);
- mHelper.createNotificationChannel(PKG, UID, channel1, true);
-
final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG, UID,
NotificationChannel.DEFAULT_CHANNEL_ID, false);
defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mHelper.updateNotificationChannel(PKG, UID, defaultChannel);
- ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, channel1.getId(),
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
NotificationChannel.DEFAULT_CHANNEL_ID);
loadStreamXml(baos);
@@ -445,12 +434,9 @@
| NotificationChannel.USER_LOCKED_VISIBILITY,
updated1.getUserLockedFields());
- // STOPSHIP - this should be reversed after the STOPSHIP is removed in the tested code.
// No Default Channel created for updated packages
- // assertEquals(null, mHelper.getNotificationChannel(UPDATED_PKG, UID2,
- // NotificationChannel.DEFAULT_CHANNEL_ID, false));
- assertTrue(mHelper.getNotificationChannel(UPDATED_PKG, UID2,
- NotificationChannel.DEFAULT_CHANNEL_ID, false) != null);
+ assertEquals(null, mHelper.getNotificationChannel(UPDATED_PKG, UID2,
+ NotificationChannel.DEFAULT_CHANNEL_ID, false));
}
@Test
@@ -466,12 +452,9 @@
when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(upgraded);
loadStreamXml(baos);
- // STOPSHIP - this should be reversed after the STOPSHIP is removed in the tested code.
// Default Channel should be gone.
- // assertEquals(null, mHelper.getNotificationChannel(PKG, UID,
- // NotificationChannel.DEFAULT_CHANNEL_ID, false));
- assertTrue(mHelper.getNotificationChannel(UPDATED_PKG, UID2,
- NotificationChannel.DEFAULT_CHANNEL_ID, false) != null);
+ assertEquals(null, mHelper.getNotificationChannel(PKG, UID,
+ NotificationChannel.DEFAULT_CHANNEL_ID, false));
}
@Test
@@ -713,20 +696,14 @@
// Returns only non-deleted channels
List<NotificationChannel> channels =
mHelper.getNotificationChannels(PKG, UID, false).getList();
- assertEquals(2, channels.size()); // Default channel + non-deleted channel
- for (NotificationChannel nc : channels) {
- if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
- compareChannels(channel2, nc);
- }
- }
+ assertEquals(1, channels.size());
+ compareChannels(channel2, channels.get(0));
// Returns deleted channels too
channels = mHelper.getNotificationChannels(PKG, UID, true).getList();
- assertEquals(3, channels.size()); // Includes default channel
+ assertEquals(2, channels.size());
for (NotificationChannel nc : channels) {
- if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
- compareChannels(channelMap.get(nc.getId()), nc);
- }
+ compareChannels(channelMap.get(nc.getId()), nc);
}
}
@@ -824,8 +801,8 @@
mHelper.permanentlyDeleteNotificationChannels(PKG, UID);
- // Only default channel remains
- assertEquals(1, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
+ // No channels remain
+ assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
}
@Test
@@ -874,13 +851,32 @@
mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
- assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
+ // since this is a pre upgrade app, clearing data should restore the default channel
+ assertEquals(1, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
+ assertEquals(NotificationChannel.DEFAULT_CHANNEL_ID,
+ mHelper.getNotificationChannels(PKG, UID, true).getList().get(0).getId());
// Not deleted
mHelper.createNotificationChannel(PKG, UID, channel1, true);
-
mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
- assertEquals(2, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
+ assertEquals(1, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
+ }
+
+ @Test
+ public void testOnPackageChanged_packageRemoval_updatedPackage() throws Exception {
+ // Deleted
+ NotificationChannel channel1 =
+ new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(UPDATED_PKG, UID2, channel1, true);
+ mHelper.onPackagesChanged(
+ true, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
+ assertEquals(0, mHelper.getNotificationChannels(UPDATED_PKG, UID2, true).getList().size());
+
+ // Not deleted
+ mHelper.createNotificationChannel(UPDATED_PKG, UID2, channel1, true);
+ mHelper.onPackagesChanged(
+ false, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
+ assertEquals(1, mHelper.getNotificationChannels(UPDATED_PKG, UID2, false).getList().size());
}
@Test
@@ -901,7 +897,23 @@
mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
- assertEquals(0, mHelper.getNotificationChannelGroups(PKG, UID, true).getList().size());
+ // default channel restored
+ assertEquals(1, mHelper.getNotificationChannelGroups(PKG, UID, true).getList().size());
+ assertNull(mHelper.getNotificationChannelGroups(PKG, UID, true).getList().get(0).getId());
+ }
+
+ @Test
+ public void testOnPackageChanged_packageRemoval_groups_upgraded() throws Exception {
+ NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
+ mHelper.createNotificationChannelGroup(UPDATED_PKG, UID2, ncg, true);
+ NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
+ mHelper.createNotificationChannelGroup(UPDATED_PKG, UID2, ncg2, true);
+
+ mHelper.onPackagesChanged(
+ true, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
+
+ assertEquals(0,
+ mHelper.getNotificationChannelGroups(UPDATED_PKG, UID2, true).getList().size());
}
@Test
@@ -975,9 +987,8 @@
assertEquals(3, actual.size());
for (NotificationChannelGroup group : actual) {
if (group.getId() == null) {
- assertEquals(2, group.getChannels().size()); // misc channel too
- assertTrue(channel3.getId().equals(group.getChannels().get(0).getId())
- || channel3.getId().equals(group.getChannels().get(1).getId()));
+ assertEquals(1, group.getChannels().size());
+ assertTrue(channel3.getId().equals(group.getChannels().get(0).getId()));
} else if (group.getId().equals(ncg.getId())) {
assertEquals(2, group.getChannels().size());
if (group.getChannels().get(0).getId().equals(channel1.getId())) {
@@ -1011,12 +1022,8 @@
List<NotificationChannelGroup> actual =
mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
- assertEquals(2, actual.size());
- for (NotificationChannelGroup group : actual) {
- if (Objects.equals(group.getId(), ncg.getId())) {
- assertEquals(1, group.getChannels().size());
- }
- }
+ assertEquals(1, actual.size());
+ assertEquals(1, actual.get(0).getChannels().size());
}
@Test
@@ -1067,7 +1074,7 @@
for (int i = 0; i < numPackages; i++) {
JSONObject object = actual.getJSONObject(i);
assertTrue(expectedChannels.containsKey(object.get("packageName")));
- assertEquals(expectedChannels.get(object.get("packageName")).intValue() + 1,
+ assertEquals(expectedChannels.get(object.get("packageName")).intValue(),
object.getInt("channelCount"));
}
}
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
index bc25860..b1cb4d7 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -312,7 +312,7 @@
TEST_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_LOW);
return new NotificationRecord(getContext(), new StatusBarNotification(
pkg, pkg, id, tag, 0, 0, n, user, null,
- System.currentTimeMillis()), notificationChannel);
+ System.currentTimeMillis()), notificationChannel, true);
}
private NotificationRecord getNotificationRecord(String pkg, int id, String tag,
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index cc682c4..fa72416 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -18,6 +18,7 @@
package="com.android.frameworks.servicestests">
<uses-permission android:name="android.permission.READ_LOGS" />
+ <uses-permission android:name="android.permission.ACCESS_VR_MANAGER" />
<uses-permission android:name="android.permission.ACCOUNT_MANAGER" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
diff --git a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
new file mode 100644
index 0000000..9a9c243
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
@@ -0,0 +1,620 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.ActivityManager;
+import android.app.AlarmManager;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+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.TwilightManager;
+import com.android.server.twilight.TwilightState;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+import java.util.Calendar;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+import static org.mockito.Mockito.doReturn;
+
+@RunWith(AndroidJUnit4.class)
+public class NightDisplayServiceTest {
+
+ private Context mContext;
+ private int mUserId;
+
+ private TwilightManager mTwilightManager;
+
+ private NightDisplayController mNightDisplayController;
+ private NightDisplayService mNightDisplayService;
+
+ @Before
+ public void setUp() {
+ mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
+ mUserId = ActivityManager.getCurrentUser();
+
+ doReturn(mContext).when(mContext).getApplicationContext();
+
+ final MockContentResolver cr = new MockContentResolver(mContext);
+ cr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ doReturn(cr).when(mContext).getContentResolver();
+
+ final AlarmManager am = Mockito.mock(AlarmManager.class);
+ doReturn(am).when(mContext).getSystemService(Context.ALARM_SERVICE);
+
+ final DisplayTransformManager dtm = Mockito.mock(DisplayTransformManager.class);
+ LocalServices.addService(DisplayTransformManager.class, dtm);
+
+ mTwilightManager = Mockito.mock(TwilightManager.class);
+ LocalServices.addService(TwilightManager.class, mTwilightManager);
+
+ mNightDisplayController = new NightDisplayController(mContext, mUserId);
+ mNightDisplayService = new NightDisplayService(mContext);
+ }
+
+ @After
+ public void tearDown() {
+ LocalServices.removeServiceForTest(DisplayTransformManager.class);
+ LocalServices.removeServiceForTest(TwilightManager.class);
+
+ mNightDisplayService = null;
+ mNightDisplayController = null;
+
+ mTwilightManager = null;
+
+ mUserId = UserHandle.USER_NULL;
+ mContext = null;
+ }
+
+ @Test
+ public void customSchedule_whenStartedAfterNight_ifOffAfterNight_turnsOff() {
+ setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
+ setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedAfterNight_ifOffBeforeNight_turnsOff() {
+ setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
+ setActivated(false /* activated */, -180 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedAfterNight_ifOffDuringNight_turnsOff() {
+ setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
+ setActivated(false /* activated */, -90 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedAfterNight_ifOffInFuture_turnsOff() {
+ setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
+ setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedAfterNight_ifOnAfterNight_turnsOn() {
+ setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
+ setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedAfterNight_ifOnBeforeNight_turnsOff() {
+ setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
+ setActivated(true /* activated */, -180 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedAfterNight_ifOnDuringNight_turnsOff() {
+ setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
+ setActivated(true /* activated */, -90 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedAfterNight_ifOnInFuture_turnsOff() {
+ setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
+ setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedBeforeNight_ifOffAfterNight_turnsOff() {
+ setAutoModeCustom(60 /* startTimeOffset */, 120 /* endTimeOffset */);
+ setActivated(false /* activated */, 180 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedBeforeNight_ifOffBeforeNight_turnsOff() {
+ setAutoModeCustom(60 /* startTimeOffset */, 120 /* endTimeOffset */);
+ setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedBeforeNight_ifOffDuringNight_turnsOff() {
+ setAutoModeCustom(60 /* startTimeOffset */, 120 /* endTimeOffset */);
+ setActivated(false /* activated */, 90 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedBeforeNight_ifOffInPast_turnsOff() {
+ setAutoModeCustom(60 /* startTimeOffset */, 120 /* endTimeOffset */);
+ setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedBeforeNight_ifOnAfterNight_turnsOff() {
+ setAutoModeCustom(60 /* startTimeOffset */, 120 /* endTimeOffset */);
+ setActivated(true /* activated */, 180 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedBeforeNight_ifOnBeforeNight_turnsOff() {
+ setAutoModeCustom(60 /* startTimeOffset */, 120 /* endTimeOffset */);
+ setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedBeforeNight_ifOnDuringNight_turnsOff() {
+ setAutoModeCustom(60 /* startTimeOffset */, 120 /* endTimeOffset */);
+ setActivated(true /* activated */, 90 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedBeforeNight_ifOnInPast_turnsOn() {
+ setAutoModeCustom(60 /* startTimeOffset */, 120 /* endTimeOffset */);
+ setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedDuringNight_ifOffAfterNight_turnsOn() {
+ setAutoModeCustom(-60 /* startTimeOffset */, 60 /* endTimeOffset */);
+ setActivated(false /* activated */, 90 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedDuringNight_ifOffBeforeNight_turnsOn() {
+ setAutoModeCustom(-60 /* startTimeOffset */, 60 /* endTimeOffset */);
+ setActivated(false /* activated */, -90 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedDuringNight_ifOffDuringNightInFuture_turnsOn() {
+ setAutoModeCustom(-60 /* startTimeOffset */, 60 /* endTimeOffset */);
+ setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedDuringNight_ifOffDuringNightInPast_turnsOff() {
+ setAutoModeCustom(-60 /* startTimeOffset */, 60 /* endTimeOffset */);
+ setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedDuringNight_ifOnAfterNight_turnsOn() {
+ setAutoModeCustom(-60 /* startTimeOffset */, 60 /* endTimeOffset */);
+ setActivated(true /* activated */, 90 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedDuringNight_ifOnBeforeNight_turnsOn() {
+ setAutoModeCustom(-60 /* startTimeOffset */, 60 /* endTimeOffset */);
+ setActivated(true /* activated */, -90 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedDuringNight_ifOnDuringNightInFuture_turnsOn() {
+ setAutoModeCustom(-60 /* startTimeOffset */, 60 /* endTimeOffset */);
+ setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void customSchedule_whenStartedDuringNight_ifOnDuringNightInPast_turnsOn() {
+ setAutoModeCustom(-60 /* startTimeOffset */, 60 /* endTimeOffset */);
+ setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedAfterNight_ifOffAfterNight_turnsOff() {
+ setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+ setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedAfterNight_ifOffBeforeNight_turnsOff() {
+ setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+ setActivated(false /* activated */, -180 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedAfterNight_ifOffDuringNight_turnsOff() {
+ setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+ setActivated(false /* activated */, -90 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedAfterNight_ifOffInFuture_turnsOff() {
+ setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+ setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedAfterNight_ifOnAfterNight_turnsOn() {
+ setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+ setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedAfterNight_ifOnBeforeNight_turnsOff() {
+ setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+ setActivated(true /* activated */, -180 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedAfterNight_ifOnDuringNight_turnsOff() {
+ setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+ setActivated(true /* activated */, -90 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedAfterNight_ifOnInFuture_turnsOff() {
+ setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+ setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedBeforeNight_ifOffAfterNight_turnsOff() {
+ setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+ setActivated(false /* activated */, 180 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedBeforeNight_ifOffBeforeNight_turnsOff() {
+ setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+ setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedBeforeNight_ifOffDuringNight_turnsOff() {
+ setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+ setActivated(false /* activated */, 90 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedBeforeNight_ifOffInPast_turnsOff() {
+ setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+ setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedBeforeNight_ifOnAfterNight_turnsOff() {
+ setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+ setActivated(true /* activated */, 180 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedBeforeNight_ifOnBeforeNight_turnsOff() {
+ setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+ setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedBeforeNight_ifOnDuringNight_turnsOff() {
+ setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+ setActivated(true /* activated */, 90 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedBeforeNight_ifOnInPast_turnsOn() {
+ setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+ setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedDuringNight_ifOffAfterNight_turnsOn() {
+ setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+ setActivated(false /* activated */, 90 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedDuringNight_ifOffBeforeNight_turnsOn() {
+ setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+ setActivated(false /* activated */, -90 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedDuringNight_ifOffDuringNightInFuture_turnsOn() {
+ setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+ setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedDuringNight_ifOffDuringNightInPast_turnsOff() {
+ setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+ setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(false /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedDuringNight_ifOnAfterNight_turnsOn() {
+ setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+ setActivated(true /* activated */, 90 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedDuringNight_ifOnBeforeNight_turnsOn() {
+ setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+ setActivated(true /* activated */, -90 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedDuringNight_ifOnDuringNightInFuture_turnsOn() {
+ setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+ setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ @Test
+ public void twilightSchedule_whenStartedDuringNight_ifOnDuringNightInPast_turnsOn() {
+ setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+ setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+ startService();
+ assertActivated(true /* activated */);
+ }
+
+ /**
+ * Convenience for making a {@link LocalTime} instance with an offset relative to now.
+ *
+ * @param offsetMinutes the offset relative to now (in minutes)
+ * @return the LocalTime instance
+ */
+ private 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));
+ }
+
+ /**
+ * Configures Night display to use a custom schedule.
+ *
+ * @param startTimeOffset the offset relative to now to activate Night display (in minutes)
+ * @param endTimeOffset the offset relative to now to deactivate Night display (in minutes)
+ */
+ private void setAutoModeCustom(int startTimeOffset, int endTimeOffset) {
+ mNightDisplayController.setAutoMode(NightDisplayController.AUTO_MODE_CUSTOM);
+ mNightDisplayController.setCustomStartTime(getLocalTimeRelativeToNow(startTimeOffset));
+ mNightDisplayController.setCustomEndTime(getLocalTimeRelativeToNow(endTimeOffset));
+ }
+
+ /**
+ * Configures Night display to use the twilight schedule.
+ *
+ * @param sunsetOffset the offset relative to now for sunset (in minutes)
+ * @param sunriseOffset the offset relative to now for sunrise (in minutes)
+ */
+ private void setAutoModeTwilight(int sunsetOffset, int sunriseOffset) {
+ mNightDisplayController.setAutoMode(NightDisplayController.AUTO_MODE_TWILIGHT);
+
+ 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();
+ if (sunsetMillis < sunriseMillis) {
+ sunsetMillis = sunset.getDateTimeAfter(now).getTimeInMillis();
+ } else {
+ sunriseMillis = sunrise.getDateTimeAfter(now).getTimeInMillis();
+ }
+
+ final TwilightState state = new TwilightState(sunriseMillis, sunsetMillis);
+ doReturn(state).when(mTwilightManager).getLastTwilightState();
+ }
+
+ /**
+ * Configures the Night display activated state.
+ *
+ * @param activated {@code true} if Night display should be activated
+ * @param lastActivatedTimeOffset the offset relative to now to record that Night display was
+ activated (in minutes)
+ */
+ 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);
+ }
+
+ /**
+ * Convenience method to start {@link #mNightDisplayService}.
+ */
+ private void startService() {
+ Secure.putIntForUser(mContext.getContentResolver(), Secure.USER_SETUP_COMPLETE, 1, mUserId);
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mNightDisplayService.onStart();
+ mNightDisplayService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+ mNightDisplayService.onStartUser(mUserId);
+ }
+ });
+ }
+
+ /**
+ * Convenience method for asserting whether Night display should be activated.
+ *
+ * @param activated the expected activated state of Night display
+ */
+ private void assertActivated(boolean activated) {
+ assertWithMessage("Invalid Night display activated state")
+ .that(mNightDisplayController.isActivated())
+ .isEqualTo(activated);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 2b4d9fb..f253632 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
import static com.android.server.wm.TaskSnapshotController.*;
import static junit.framework.Assert.assertEquals;
@@ -76,12 +77,19 @@
public void testGetSnapshotMode() throws Exception {
final WindowState disabledWindow = createWindow(null,
FIRST_APPLICATION_WINDOW, mDisplayContent, "disabledWindow");
- disabledWindow.mAppToken.setDisablePreviewSnapshots(true);
+ disabledWindow.mAppToken.setDisablePreviewScreenshots(true);
assertEquals(SNAPSHOT_MODE_APP_THEME,
sWm.mTaskSnapshotController.getSnapshotMode(disabledWindow.getTask()));
+
final WindowState normalWindow = createWindow(null,
FIRST_APPLICATION_WINDOW, mDisplayContent, "normalWindow");
assertEquals(SNAPSHOT_MODE_REAL,
sWm.mTaskSnapshotController.getSnapshotMode(normalWindow.getTask()));
+
+ final WindowState secureWindow = createWindow(null,
+ FIRST_APPLICATION_WINDOW, mDisplayContent, "secureWindow");
+ secureWindow.mAttrs.flags |= FLAG_SECURE;
+ assertEquals(SNAPSHOT_MODE_APP_THEME,
+ sWm.mTaskSnapshotController.getSnapshotMode(secureWindow.getTask()));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index 717ddf2..e2868d7 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -171,11 +171,25 @@
final Canvas mockCanvas = mock(Canvas.class);
when(mockCanvas.getWidth()).thenReturn(100);
when(mockCanvas.getHeight()).thenReturn(100);
- mSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 50, 100), 10);
+ mSurface.mSystemBarBackgroundPainter.drawStatusBarBackground(
+ mockCanvas, new Rect(0, 0, 50, 100), 10);
verify(mockCanvas).drawRect(eq(50.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
}
@Test
+ public void testDrawStatusBarBackground_nullFrame() {
+ setupSurface(100, 100);
+ final Rect insets = new Rect(0, 10, 10, 0);
+ mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mSurface.mSystemBarBackgroundPainter.drawStatusBarBackground(
+ mockCanvas, null, 10);
+ verify(mockCanvas).drawRect(eq(0.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
+ }
+
+ @Test
public void testDrawStatusBarBackground_nope() {
setupSurface(100, 100);
final Rect insets = new Rect(0, 10, 10, 0);
@@ -183,7 +197,8 @@
final Canvas mockCanvas = mock(Canvas.class);
when(mockCanvas.getWidth()).thenReturn(100);
when(mockCanvas.getHeight()).thenReturn(100);
- mSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 100, 100), 10);
+ mSurface.mSystemBarBackgroundPainter.drawStatusBarBackground(
+ mockCanvas, new Rect(0, 0, 100, 100), 10);
verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
}
@@ -196,7 +211,7 @@
final Canvas mockCanvas = mock(Canvas.class);
when(mockCanvas.getWidth()).thenReturn(100);
when(mockCanvas.getHeight()).thenReturn(100);
- mSurface.drawNavigationBarBackground(mockCanvas);
+ mSurface.mSystemBarBackgroundPainter.drawNavigationBarBackground(mockCanvas);
verify(mockCanvas).drawRect(eq(new Rect(0, 90, 100, 100)), any());
}
@@ -209,7 +224,7 @@
final Canvas mockCanvas = mock(Canvas.class);
when(mockCanvas.getWidth()).thenReturn(100);
when(mockCanvas.getHeight()).thenReturn(100);
- mSurface.drawNavigationBarBackground(mockCanvas);
+ mSurface.mSystemBarBackgroundPainter.drawNavigationBarBackground(mockCanvas);
verify(mockCanvas).drawRect(eq(new Rect(0, 0, 10, 100)), any());
}
@@ -222,7 +237,7 @@
final Canvas mockCanvas = mock(Canvas.class);
when(mockCanvas.getWidth()).thenReturn(100);
when(mockCanvas.getHeight()).thenReturn(100);
- mSurface.drawNavigationBarBackground(mockCanvas);
+ mSurface.mSystemBarBackgroundPainter.drawNavigationBarBackground(mockCanvas);
verify(mockCanvas).drawRect(eq(new Rect(90, 0, 100, 100)), any());
}
}
diff --git a/tests/radio/src/android/hardware/radio/tests/RadioTest.java b/tests/radio/src/android/hardware/radio/tests/RadioTest.java
index e9c9b8c..7ab5618 100644
--- a/tests/radio/src/android/hardware/radio/tests/RadioTest.java
+++ b/tests/radio/src/android/hardware/radio/tests/RadioTest.java
@@ -22,6 +22,7 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
+import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
@@ -30,6 +31,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import static org.junit.Assert.*;
@@ -37,6 +39,7 @@
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -48,6 +51,8 @@
public final Context mContext = InstrumentationRegistry.getContext();
+ private final int kConfigCallbacktimeoutNs = 10000;
+
private RadioManager mRadioManager;
private RadioTuner mRadioTuner;
private final List<RadioManager.ModuleProperties> mModules = new ArrayList<>();
@@ -56,6 +61,9 @@
RadioManager.AmBandDescriptor mAmBandDescriptor;
RadioManager.FmBandDescriptor mFmBandDescriptor;
+ RadioManager.BandConfig mAmBandConfig;
+ RadioManager.BandConfig mFmBandConfig;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -98,11 +106,14 @@
}
assertNotNull(mAmBandDescriptor);
assertNotNull(mFmBandDescriptor);
- RadioManager.BandConfig fmBandConfig =
- new RadioManager.FmBandConfig.Builder(mFmBandDescriptor).build();
+ mAmBandConfig = new RadioManager.AmBandConfig.Builder(mAmBandDescriptor).build();
+ mFmBandConfig = new RadioManager.FmBandConfig.Builder(mFmBandDescriptor).build();
- mRadioTuner = mRadioManager.openTuner(module.getId(), fmBandConfig, true, mCallback, null);
+ mRadioTuner = mRadioManager.openTuner(module.getId(), mFmBandConfig, true, mCallback, null);
assertNotNull(mRadioTuner);
+ verify(mCallback, timeout(kConfigCallbacktimeoutNs).times(1)).onConfigurationChanged(any());
+ verify(mCallback, never()).onError(anyInt());
+ Mockito.reset(mCallback);
}
@Test
@@ -112,26 +123,59 @@
}
@Test
- public void testReopenTuner() {
+ public void testReopenTuner() throws Throwable {
openTuner();
mRadioTuner.close();
mRadioTuner = null;
+ Thread.sleep(100); // TODO(b/36122635): force reopen
openTuner();
verify(mCallback, never()).onError(anyInt());
}
@Test
- @org.junit.Ignore("setConfiguration is not implemented yet")
public void testSetAndGetConfiguration() {
openTuner();
- RadioManager.BandConfig amBandConfig =
- new RadioManager.AmBandConfig.Builder(mAmBandDescriptor).build();
- mRadioTuner.setConfiguration(amBandConfig);
+ // set
+ int ret = mRadioTuner.setConfiguration(mAmBandConfig);
+ assertEquals(RadioManager.STATUS_OK, ret);
+ verify(mCallback, timeout(kConfigCallbacktimeoutNs).times(1)).onConfigurationChanged(any());
- verify(mCallback, times(1)).onConfigurationChanged(any());
+ // get
+ RadioManager.BandConfig[] config = new RadioManager.BandConfig[1];
+ ret = mRadioTuner.getConfiguration(config);
+ assertEquals(RadioManager.STATUS_OK, ret);
+
verify(mCallback, never()).onError(anyInt());
+ assertEquals(mAmBandConfig, config[0]);
+ }
- // TODO(b/36863239): implement "get" too
+ @Test
+ public void testSetBadConfiguration() throws Throwable {
+ openTuner();
+
+ // set bad config
+ Constructor<RadioManager.AmBandConfig> configConstr =
+ RadioManager.AmBandConfig.class.getDeclaredConstructor(
+ int.class, int.class, int.class, int.class, int.class, boolean.class);
+ configConstr.setAccessible(true);
+ RadioManager.AmBandConfig badConfig = configConstr.newInstance(
+ 0 /*region*/, RadioManager.BAND_AM /*type*/,
+ 10000 /*lowerLimit*/, 1 /*upperLimit*/, 100 /*spacing*/, false /*stereo*/);
+ int ret = mRadioTuner.setConfiguration(badConfig);
+ assertEquals(RadioManager.STATUS_BAD_VALUE, ret);
+ verify(mCallback, never()).onConfigurationChanged(any());
+
+ // set null config
+ ret = mRadioTuner.setConfiguration(null);
+ assertEquals(RadioManager.STATUS_BAD_VALUE, ret);
+ verify(mCallback, never()).onConfigurationChanged(any());
+
+ // setting good config should recover
+ ret = mRadioTuner.setConfiguration(mAmBandConfig);
+ assertEquals(RadioManager.STATUS_OK, ret);
+ verify(mCallback, timeout(kConfigCallbacktimeoutNs).times(1)).onConfigurationChanged(any());
+
+ verify(mCallback, never()).onError(anyInt());
}
}
diff --git a/tests/testables/src/android/testing/TestableContext.java b/tests/testables/src/android/testing/TestableContext.java
index 630a287..d6c06e4 100644
--- a/tests/testables/src/android/testing/TestableContext.java
+++ b/tests/testables/src/android/testing/TestableContext.java
@@ -69,6 +69,7 @@
private LeakCheck.Tracker mReceiver;
private LeakCheck.Tracker mService;
private LeakCheck.Tracker mComponent;
+ private TestableResources mTestableResources;
public TestableContext(Context base) {
this(base, null);
@@ -98,9 +99,37 @@
return super.getPackageManager();
}
+ /**
+ * Makes sure the resources being returned by this TestableContext are a version of
+ * TestableResources.
+ * @see #getResources()
+ */
+ public void ensureTestableResources() {
+ if (mTestableResources == null) {
+ mTestableResources = new TestableResources(super.getResources());
+ }
+ }
+
+ /**
+ * Get (and create if necessary) {@link TestableResources} for this TestableContext.
+ */
+ public TestableResources getOrCreateTestableResources() {
+ ensureTestableResources();
+ return mTestableResources;
+ }
+
+ /**
+ * Returns a Resources instance for the test.
+ *
+ * By default this returns the same resources object that would come from the
+ * {@link ContextWrapper}, but if {@link #ensureTestableResources()} or
+ * {@link #getOrCreateTestableResources()} has been called, it will return resources gotten from
+ * {@link TestableResources}.
+ */
@Override
public Resources getResources() {
- return super.getResources();
+ return mTestableResources != null ? mTestableResources.getResources()
+ : super.getResources();
}
public <T> void addMockSystemService(Class<T> service, T mock) {
diff --git a/tests/testables/src/android/testing/TestableResources.java b/tests/testables/src/android/testing/TestableResources.java
new file mode 100644
index 0000000..a2fa95d
--- /dev/null
+++ b/tests/testables/src/android/testing/TestableResources.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package android.testing;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.withSettings;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
+import android.util.SparseArray;
+
+import org.mockito.invocation.InvocationOnMock;
+
+/**
+ * Provides a version of Resources that defaults to all existing resources, but can have ids
+ * changed to return specific values.
+ * <p>
+ * TestableResources are lazily initialized, be sure to call
+ * {@link TestableContext#ensureTestableResources} before your tested code has an opportunity
+ * to cache {@link Context#getResources}.
+ * </p>
+ */
+public class TestableResources {
+
+ private static final String TAG = "TestableResources";
+ private final Resources mResources;
+ private final SparseArray<Object> mOverrides = new SparseArray<>();
+
+ TestableResources(Resources realResources) {
+ mResources = mock(Resources.class, withSettings()
+ .spiedInstance(realResources)
+ .defaultAnswer(this::answer));
+ }
+
+ /**
+ * Gets the implementation of Resources that will return overridden values when called.
+ */
+ public Resources getResources() {
+ return mResources;
+ }
+
+ /**
+ * Sets the return value for the specified resource id.
+ * <p>
+ * Since resource ids are unique there is a single addOverride that will override the value
+ * whenever it is gotten regardless of which method is used (i.e. getColor or getDrawable).
+ * </p>
+ * @param id The resource id to be overridden
+ * @param value The value of the resource, null to cause a {@link Resources.NotFoundException}
+ * when gotten.
+ */
+ public void addOverride(int id, Object value) {
+ mOverrides.put(id, value);
+ }
+
+ /**
+ * Removes the override for the specified id.
+ * <p>
+ * This should be called over addOverride(id, null), because specifying a null value will
+ * cause a {@link Resources.NotFoundException} whereas removing the override will actually
+ * switch back to returning the default/real value of the resource.
+ * </p>
+ * @param id
+ */
+ public void removeOverride(int id) {
+ mOverrides.remove(id);
+ }
+
+ private Object answer(InvocationOnMock invocationOnMock) throws Throwable {
+ try {
+ int id = invocationOnMock.getArgument(0);
+ int index = mOverrides.indexOfKey(id);
+ if (index >= 0) {
+ Object value = mOverrides.valueAt(index);
+ if (value == null) throw new Resources.NotFoundException();
+ return value;
+ }
+ } catch (Resources.NotFoundException e) {
+ // Let through NotFoundException.
+ throw e;
+ } catch (Throwable t) {
+ // Generic catching for the many things that can go wrong, fall back to
+ // the real implementation.
+ Log.i(TAG, "Falling back to default resources call " + t);
+ }
+ return invocationOnMock.callRealMethod();
+ }
+}
diff --git a/tests/testables/tests/res/values/strings.xml b/tests/testables/tests/res/values/strings.xml
new file mode 100644
index 0000000..1ad0ade
--- /dev/null
+++ b/tests/testables/tests/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="test_string">This is a test string</string>
+</resources>
diff --git a/tests/testables/tests/src/android/testing/TestableResourcesTest.java b/tests/testables/tests/src/android/testing/TestableResourcesTest.java
new file mode 100644
index 0000000..9a1c0a9
--- /dev/null
+++ b/tests/testables/tests/src/android/testing/TestableResourcesTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package android.testing;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import android.content.res.Resources;
+import android.support.test.InstrumentationRegistry;
+
+import com.android.testables.R;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+public class TestableResourcesTest {
+
+ @Rule
+ public TestableContext mContext = new TestableContext(InstrumentationRegistry.getContext());
+
+ @Test
+ public void testLazyInit() {
+ Resources before = mContext.getResources();
+ mContext.ensureTestableResources();
+ Resources after = mContext.getResources();
+ assertNotEquals(before, after);
+ }
+
+ @Test
+ public void testAddingResource() {
+ final int nonExistentId = 3; // Ids don't go this low.
+
+ try {
+ mContext.getColor(nonExistentId);
+ fail("Should throw NotFoundException");
+ } catch (Resources.NotFoundException e) {
+ }
+ mContext.getOrCreateTestableResources().addOverride(nonExistentId, 0xffffff);
+
+ assertEquals(0xffffff, mContext.getColor(nonExistentId));
+ }
+
+ @Test
+ public void testClearingResource() {
+ final int nonExistentId = 3; // Ids don't go this low.
+
+ mContext.getOrCreateTestableResources().addOverride(nonExistentId, 0xffffff);
+ assertEquals(0xffffff, mContext.getColor(nonExistentId));
+ mContext.getOrCreateTestableResources().removeOverride(nonExistentId);
+ try {
+ mContext.getColor(nonExistentId);
+ fail("Should throw NotFoundException");
+ } catch (Resources.NotFoundException e) {
+ }
+ }
+
+ @Test
+ public void testOverrideExisting() {
+ int existentId = R.string.test_string;
+
+ assertNotNull(mContext.getString(existentId));
+ mContext.getOrCreateTestableResources().addOverride(existentId, "Other strings");
+
+ assertEquals("Other strings", mContext.getString(existentId));
+ }
+
+ @Test(expected = Resources.NotFoundException.class)
+ public void testNonExistentException() {
+ int existentId = R.string.test_string;
+
+ assertNotNull(mContext.getString(existentId));
+ mContext.getOrCreateTestableResources().addOverride(existentId, null);
+
+ assertNull(mContext.getString(existentId));
+ }
+}
\ No newline at end of file