Merge "If ENSURE_VERIFY_APPS is enforced, reject installation by default." into oc-dev
diff --git a/Android.mk b/Android.mk
index 8f99bc0..b5f8cb0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1061,6 +1061,7 @@
-showAnnotation android.annotation.SystemApi \
-api $(INTERNAL_PLATFORM_SYSTEM_API_FILE) \
-removedApi $(INTERNAL_PLATFORM_SYSTEM_REMOVED_API_FILE) \
+ -exactApi $(INTERNAL_PLATFORM_SYSTEM_EXACT_API_FILE) \
-nodocs
LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
@@ -1097,6 +1098,7 @@
-showAnnotation android.annotation.TestApi \
-api $(INTERNAL_PLATFORM_TEST_API_FILE) \
-removedApi $(INTERNAL_PLATFORM_TEST_REMOVED_API_FILE) \
+ -exactApi $(INTERNAL_PLATFORM_TEST_EXACT_API_FILE) \
-nodocs
LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
@@ -1250,8 +1252,6 @@
include $(BUILD_DROIDDOC)
# ==== docs for the web (on the androiddevdocs app engine server) =======================
-# TODO: Fix the System API docs build.
-ifneq ($(filter online-system-api-sdk-docs,$(MAKECMDGOALS)),)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
@@ -1282,11 +1282,10 @@
-samplesdir $(samples_dir)
LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
-# Don't build by default
+
LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_DROIDDOC)
-endif # online-system-api-sdk-docs in make command line.
# ==== docs for the web (on the devsite app engine server) =======================
include $(CLEAR_VARS)
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 26ac6ad..4dea0e0 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -131,6 +131,7 @@
import java.util.HashMap;
import java.util.List;
+import static android.os.Build.VERSION_CODES.O;
import static java.lang.Character.MIN_VALUE;
/**
@@ -974,6 +975,18 @@
@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState) {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
+
+ if (getApplicationInfo().targetSdkVersion >= O && mActivityInfo.isFixedOrientation()) {
+ final TypedArray ta = obtainStyledAttributes(com.android.internal.R.styleable.Window);
+ final boolean isTranslucentOrFloating = ActivityInfo.isTranslucentOrFloating(ta);
+ ta.recycle();
+
+ if (isTranslucentOrFloating) {
+ throw new IllegalStateException(
+ "Only fullscreen opaque activities can request orientation");
+ }
+ }
+
if (mLastNonConfigurationInstances != null) {
mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 587ab3b..9a01476 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -20,6 +20,7 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Configuration.NativeConfig;
+import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Printer;
@@ -440,7 +441,6 @@
* @hide
*/
public static final int FLAG_SUPPORTS_PICTURE_IN_PICTURE = 0x400000;
-
/**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the system user. Only works with broadcast receivers. Set from the
@@ -978,12 +978,20 @@
* Returns true if the activity's orientation is fixed.
* @hide
*/
- boolean isFixedOrientation() {
+ public boolean isFixedOrientation() {
return isFixedOrientationLandscape() || isFixedOrientationPortrait()
|| screenOrientation == SCREEN_ORIENTATION_LOCKED;
}
/**
+ * Returns true if the specified orientation is considered fixed.
+ * @hide
+ */
+ static public boolean isFixedOrientation(int orientation) {
+ return isFixedOrientationLandscape(orientation) || isFixedOrientationPortrait(orientation);
+ }
+
+ /**
* Returns true if the activity's orientation is fixed to landscape.
* @hide
*/
@@ -1162,6 +1170,25 @@
dest.writeFloat(maxAspectRatio);
}
+ /**
+ * Determines whether the {@link Activity} is considered translucent or floating.
+ * @hide
+ */
+ public static boolean isTranslucentOrFloating(TypedArray attributes) {
+ final boolean isTranslucent =
+ attributes.getBoolean(com.android.internal.R.styleable.Window_windowIsTranslucent,
+ false);
+ final boolean isSwipeToDismiss = !attributes.hasValue(
+ com.android.internal.R.styleable.Window_windowIsTranslucent)
+ && attributes.getBoolean(
+ com.android.internal.R.styleable.Window_windowSwipeToDismiss, false);
+ final boolean isFloating =
+ attributes.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating,
+ false);
+
+ return isFloating || isTranslucent || isSwipeToDismiss;
+ }
+
public static final Parcelable.Creator<ActivityInfo> CREATOR
= new Parcelable.Creator<ActivityInfo>() {
public ActivityInfo createFromParcel(Parcel source) {
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 3267172..244c7a2 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -340,7 +340,12 @@
private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) {
Display display = mDisplays.get(displayId);
if (display == null) {
- display = mGlobal.getCompatibleDisplay(displayId, mContext.getResources());
+ // TODO: We cannot currently provide any override configurations for metrics on displays
+ // other than the display the context is associated with.
+ final Context context = mContext.getDisplay().getDisplayId() == displayId
+ ? mContext : mContext.getApplicationContext();
+
+ display = mGlobal.getCompatibleDisplay(displayId, context.getResources());
if (display != null) {
mDisplays.put(displayId, display);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f418435..18cfc99 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1314,6 +1314,13 @@
<permission android:name="android.permission.NETWORK_STACK"
android:protectionLevel="signature" />
+ <!-- Allows Settings and SystemUI to call methods in Networking services
+ <p>Not for use by third-party or privileged applications.
+ @hide This should only be used by Settings and SystemUI.
+ -->
+ <permission android:name="android.permission.NETWORK_SETTINGS"
+ android:protectionLevel="signature" />
+
<!-- ======================================= -->
<!-- Permissions for short range, peripheral networks -->
<!-- ======================================= -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index aeb564b..8b9b0e2 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2876,4 +2876,7 @@
<!-- Handle volume keys directly in Window Manager without passing them to the foreground app -->
<bool name="config_handleVolumeKeysInWindowManager">false</bool>
+ <!-- Volume level of in-call notification tone playback,
+ relative to the overall voice call stream volume [0..100] -->
+ <integer name="config_inCallNotificationVolumeRelative">67</integer>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 72011e8..cb1851b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4484,7 +4484,7 @@
<item quantity="other"><xliff:g id="count" example="3">%1$d</xliff:g> selected</item>
</plurals>
- <string name="default_notification_channel_label">Miscellaneous</string>
+ <string name="default_notification_channel_label">Uncategorized</string>
<string name="importance_from_user">You set the importance of these notifications.</string>
<string name="importance_from_person">This is important because of the people involved.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2aab590..3551bc9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3013,4 +3013,6 @@
<java-symbol type="array" name="config_allowedSecureInstantAppSettings" />
<java-symbol type="bool" name="config_handleVolumeKeysInWindowManager" />
+
+ <java-symbol type="integer" name="config_inCallNotificationVolumeRelative" />
</resources>
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index ea804d0..3fe730f 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -599,9 +599,9 @@
private final Context context;
private final ServiceConnection serviceConnection;
private final IKeyChainService service;
- private KeyChainConnection(Context context,
- ServiceConnection serviceConnection,
- IKeyChainService service) {
+ protected KeyChainConnection(Context context,
+ ServiceConnection serviceConnection,
+ IKeyChainService service) {
this.context = context;
this.serviceConnection = serviceConnection;
this.service = service;
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index dd66649..9bd93aa 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -35,6 +35,7 @@
import com.android.internal.app.IAppOpsService;
import java.lang.IllegalArgumentException;
+import java.lang.ref.WeakReference;
import java.util.Objects;
/**
@@ -45,11 +46,11 @@
*/
public abstract class PlayerBase {
- private final static String TAG = "PlayerBase";
- private final static boolean DEBUG = false;
+ private static final String TAG = "PlayerBase";
+ private static final boolean DEBUG = false;
private static IAudioService sService; //lazy initialization, use getService()
/** Debug app ops */
- protected static final boolean DEBUG_APP_OPS = Log.isLoggable(TAG + ".AO", Log.DEBUG);
+ private static final boolean DEBUG_APP_OPS = false;
// parameters of the player that affect AppOps
protected AudioAttributes mAttributes;
@@ -94,19 +95,9 @@
IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
mAppOps = IAppOpsService.Stub.asInterface(b);
// initialize mHasAppOpsPlayAudio
- synchronized (mLock) {
- updateAppOpsPlayAudio_sync();
- }
+ updateAppOpsPlayAudio();
// register a callback to monitor whether the OP_PLAY_AUDIO is still allowed
- mAppOpsCallback = new IAppOpsCallback.Stub() {
- public void opChanged(int op, int uid, String packageName) {
- synchronized (mLock) {
- if (op == AppOpsManager.OP_PLAY_AUDIO) {
- updateAppOpsPlayAudio_sync();
- }
- }
- }
- };
+ mAppOpsCallback = new IAppOpsCallbackWrapper(this);
try {
mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO,
ActivityThread.currentPackageName(), mAppOpsCallback);
@@ -114,10 +105,8 @@
mHasAppOpsPlayAudio = false;
}
try {
- if (mIPlayer == null) {
- throw new IllegalStateException("Cannot register a player with a null mIPlayer");
- }
- newPiid = getService().trackPlayer(new PlayerIdCard(mImplType, mAttributes, mIPlayer));
+ newPiid = getService().trackPlayer(
+ new PlayerIdCard(mImplType, mAttributes, new IPlayerWrapper(this)));
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, player will not be tracked", e);
}
@@ -259,6 +248,12 @@
}
}
+ private void updateAppOpsPlayAudio() {
+ synchronized (mLock) {
+ updateAppOpsPlayAudio_sync();
+ }
+ }
+
/**
* To be called whenever a condition that might affect audibility of this player is updated.
* Must be called synchronized on mLock.
@@ -406,47 +401,95 @@
abstract void playerStop();
//=====================================================================
+ private static class IAppOpsCallbackWrapper extends IAppOpsCallback.Stub {
+ private final WeakReference<PlayerBase> mWeakPB;
+
+ public IAppOpsCallbackWrapper(PlayerBase pb) {
+ mWeakPB = new WeakReference<PlayerBase>(pb);
+ }
+
+ @Override
+ public void opChanged(int op, int uid, String packageName) {
+ if (op == AppOpsManager.OP_PLAY_AUDIO) {
+ if (DEBUG_APP_OPS) { Log.v(TAG, "opChanged: op=PLAY_AUDIO pack=" + packageName); }
+ final PlayerBase pb = mWeakPB.get();
+ if (pb != null) {
+ pb.updateAppOpsPlayAudio();
+ }
+ }
+ }
+ }
+
+ //=====================================================================
/**
- * Implementation of IPlayer for all subclasses of PlayerBase
+ * Wrapper around an implementation of IPlayer for all subclasses of PlayerBase
+ * that doesn't keep a strong reference on PlayerBase
*/
- private IPlayer mIPlayer = new IPlayer.Stub() {
+ private static class IPlayerWrapper extends IPlayer.Stub {
+ private final WeakReference<PlayerBase> mWeakPB;
+
+ public IPlayerWrapper(PlayerBase pb) {
+ mWeakPB = new WeakReference<PlayerBase>(pb);
+ }
+
@Override
public void start() {
- playerStart();
+ final PlayerBase pb = mWeakPB.get();
+ if (pb != null) {
+ pb.playerStart();
+ }
}
@Override
public void pause() {
- playerPause();
+ final PlayerBase pb = mWeakPB.get();
+ if (pb != null) {
+ pb.playerPause();
+ }
}
@Override
public void stop() {
- playerStop();
+ final PlayerBase pb = mWeakPB.get();
+ if (pb != null) {
+ pb.playerStop();
+ }
}
@Override
public void setVolume(float vol) {
- baseSetVolume(vol, vol);
+ final PlayerBase pb = mWeakPB.get();
+ if (pb != null) {
+ pb.baseSetVolume(vol, vol);
+ }
}
@Override
public void setPan(float pan) {
- baseSetPan(pan);
+ final PlayerBase pb = mWeakPB.get();
+ if (pb != null) {
+ pb.baseSetPan(pan);
+ }
}
@Override
public void setStartDelayMs(int delayMs) {
- baseSetStartDelayMs(delayMs);
+ final PlayerBase pb = mWeakPB.get();
+ if (pb != null) {
+ pb.baseSetStartDelayMs(delayMs);
+ }
}
@Override
public void applyVolumeShaper(
@NonNull VolumeShaper.Configuration configuration,
@NonNull VolumeShaper.Operation operation) {
- /* void */ playerApplyVolumeShaper(configuration, operation);
+ final PlayerBase pb = mWeakPB.get();
+ if (pb != null) {
+ pb.playerApplyVolumeShaper(configuration, operation);
+ }
}
- };
+ }
//=====================================================================
/**
@@ -455,8 +498,8 @@
public static class PlayerIdCard implements Parcelable {
public final int mPlayerType;
- public final static int AUDIO_ATTRIBUTES_NONE = 0;
- public final static int AUDIO_ATTRIBUTES_DEFINED = 1;
+ public static final int AUDIO_ATTRIBUTES_NONE = 0;
+ public static final int AUDIO_ATTRIBUTES_DEFINED = 1;
public final AudioAttributes mAttributes;
public final IPlayer mIPlayer;
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index e774c71..3eb9d52 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -943,7 +943,8 @@
// Sanity-check: are we actually being asked to install an audio file?
final String mimeType = mContext.getContentResolver().getType(fileUri);
- if(mimeType == null || !mimeType.startsWith("audio/")) {
+ if(mimeType == null ||
+ !(mimeType.startsWith("audio/") || mimeType.equals("application/ogg"))) {
throw new IllegalArgumentException("Ringtone file must have MIME type \"audio/*\"."
+ " Given file has MIME type \"" + mimeType + "\"");
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 490bee4..290ce1f 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -528,7 +528,7 @@
<activity
android:name=".settings.BrightnessDialog"
android:label="@string/quick_settings_brightness_dialog_title"
- android:theme="@android:style/Theme.DeviceDefault.Dialog"
+ android:theme="@android:style/Theme.DeviceDefault.Light.Dialog"
android:finishOnCloseSystemDialogs="true"
android:launchMode="singleInstance"
android:excludeFromRecents="true"
diff --git a/packages/SystemUI/res/drawable/ic_data_unavailable.xml b/packages/SystemUI/res/drawable/ic_data_unavailable.xml
index 27a7697..ffb2af7 100644
--- a/packages/SystemUI/res/drawable/ic_data_unavailable.xml
+++ b/packages/SystemUI/res/drawable/ic_data_unavailable.xml
@@ -12,7 +12,6 @@
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.
- M12.0,12.0m-9.5,0.0a9.5,9.5 0.0,1.0 1.0,19.0 0.0a9.5,9.5 0.0,1.0 1.0,-19.0 0.0
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24.0dp"
@@ -20,13 +19,9 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:pathData="M12.0,2.5c-5.246705,0.0 -9.5,4.253295 -9.5,9.5 0.0,5.246705 4.253295,9.5 9.5,9.5 2.771732,0.0 5.263364,-1.200342 7.0,-3.09375l0.0,-0.21875 0.0,-7.5 0.0,-1.0 1.0,0.0 1.1875,0.0C20.148497,5.5674677 16.442669,2.5 12.0,2.5zm9.1875,7.1875c-14.125,9.541667 -7.0625,4.770833 0.0,0.0z
- M10.6,5.4C10.4,5.2 10.1,5.2 10.0,5.4L7.6,9.1l2.0,0.0l0.0,3.8L11.0,12.900001L11.0,9.1l2.0,0.0L10.6,5.4z
- M13.3,18.6c0.2,0.2 0.5,0.2 0.6,0.0l2.4,-3.7l-2.0,0.0l0.0,-3.8l-1.4,0.0l0.0,3.8l-2.0,0.0l2.4,3.7z
- M21.7,24.0c-0.5,0.0 -0.8,-0.1 -1.1,-0.4c-0.3,-0.3 -0.4,-0.6 -0.4,-1.0c0.0,-0.4 0.1,-0.8 0.4,-1.0c0.3,-0.3 0.7,-0.4 1.1,-0.4s0.8,0.1 1.1,0.4c0.3,0.3 0.4,0.6 0.4,1.0c0.0,0.4 -0.1,0.7 -0.4,1.0
- C22.6,23.8 22.2,24 21.7,24z
- M20.4,19.7l0.0,-8.5L23.0,11.2l0.0,8.5L20.4,19.7z
- "
- android:fillType="evenOdd"
- android:fillColor="#231F20"/>
+ android:pathData="M15.8,12.9l3.7,0.0c0.0,-0.3 0.0,-0.6 0.0,-0.9c0.0,-5.2 -4.3,-9.5 -9.5,-9.5S0.6,6.8 0.6,12.0s4.3,9.5 9.5,9.5c2.1,0.0 4.1,-0.7 5.7,-1.9L15.8,12.9zM5.7,9.1l2.4,-3.7c0.2,-0.2 0.5,-0.2 0.6,0.0l2.4,3.7l-2.0,0.0l0.0,3.8L7.8,12.900001L7.8,9.1L5.7,9.1zM11.4,18.6L9.0,14.9l2.0,0.0l0.0,-3.8l1.4,0.0l0.0,3.8l2.0,0.0L12.0,18.6C11.9,18.8 11.6,18.8 11.4,18.6z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M23.4,19.4l-2.1,-2.1 2.1,-2.199999 -1.1,-1.0 -2.099998,2.1 -2.1,-2.1 -1.1,1.099999 2.1,2.099999 -2.1,2.1 1.1,1.1 2.1,-2.200001 2.099998,2.200001z"
+ android:fillColor="#FFFFFF"/>
</vector>
diff --git a/packages/SystemUI/res/layout/volume_zen_footer.xml b/packages/SystemUI/res/layout/volume_zen_footer.xml
index 775b157..91dc617 100644
--- a/packages/SystemUI/res/layout/volume_zen_footer.xml
+++ b/packages/SystemUI/res/layout/volume_zen_footer.xml
@@ -29,6 +29,52 @@
android:layout_marginTop="8dp"
android:background="@color/qs_tile_divider" />
+
+ <RelativeLayout
+ android:id="@+id/zen_introduction"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="16dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:background="@drawable/zen_introduction_message_background"
+ android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent.Light">
+
+ <ImageView
+ android:id="@+id/zen_introduction_confirm"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginEnd="8dp"
+ android:layout_alignParentEnd="true"
+ android:background="@drawable/btn_borderless_rect"
+ android:clickable="true"
+ android:contentDescription="@string/accessibility_desc_close"
+ android:scaleType="center"
+ android:src="@drawable/ic_close"
+ android:tint="@android:color/white" />
+
+ <TextView
+ android:id="@+id/zen_introduction_message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dp"
+ android:layout_marginStart="24dp"
+ android:textDirection="locale"
+ android:lineSpacingMultiplier="1.20029"
+ android:layout_toStartOf="@id/zen_introduction_confirm"
+ android:text="@string/zen_alarms_introduction"
+ android:textAppearance="@style/TextAppearance.QS.Introduction" />
+
+ <View
+ android:layout_width="0dp"
+ android:layout_height="16dp"
+ android:layout_below="@id/zen_introduction_message"
+ android:layout_alignParentEnd="true" />
+
+ </RelativeLayout>
+
+
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d15fcae..64b5f4b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -838,7 +838,10 @@
<string name="description_direction_left">"Slide left for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
<!-- Zen mode: Priority only introduction message on first use -->
- <string name="zen_priority_introduction">You won’t be disturbed by sounds and vibrations, except from alarms, reminders, events, and callers you specify.</string>
+ <string name="zen_priority_introduction">You won’t be disturbed by sounds and vibrations, except from alarms, reminders, events, and callers you specify. You'll still hear anything you choose to play including music, videos, and games.</string>
+
+ <!-- Zen mode: Alarms only introduction message on first use -->
+ <string name="zen_alarms_introduction">You won’t be disturbed by sounds and vibrations, except from alarms. You'll still hear anything you choose to play including music, videos, and games.</string>
<!-- Zen mode: Priority only customization button label -->
<string name="zen_priority_customize_button">Customize</string>
@@ -1211,7 +1214,7 @@
<string name="zen_mode_and_condition"><xliff:g id="zen_mode" example="Priority interruptions only">%1$s</xliff:g>. <xliff:g id="exit_condition" example="For one hour">%2$s</xliff:g></string>
<!-- Button label for ending zen mode in the volume dialog -->
- <string name="volume_zen_end_now">End now</string>
+ <string name="volume_zen_end_now">Turn off now</string>
<!-- Content description for accessibility (not shown on the screen): volume dialog expand button. [CHAR LIMIT=NONE] -->
<string name="accessibility_volume_expand">Expand</string>
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 1e9cbdc..3cc81df 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -58,6 +58,7 @@
String DND_TILE_COMBINED_ICON = "DndTileCombinedIcon";
String DND_CONFIRMED_PRIORITY_INTRODUCTION = "DndConfirmedPriorityIntroduction";
String DND_CONFIRMED_SILENCE_INTRODUCTION = "DndConfirmedSilenceIntroduction";
+ String DND_CONFIRMED_ALARM_INTRODUCTION = "DndConfirmedAlarmIntroduction";
String DND_FAVORITE_BUCKET_INDEX = "DndCountdownMinuteIndex";
String DND_NONE_SELECTED = "DndNoneSelected";
String DND_FAVORITE_ZEN = "DndFavoriteZen";
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 07bd242..88e8b39 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1585,7 +1585,6 @@
updateInputRestricted();
}
- mDismissCallbackRegistry.notifyDismissSucceeded();
handleHide();
Trace.endSection();
}
@@ -1798,6 +1797,7 @@
resetKeyguardDonePendingLocked();
mHideAnimationRun = false;
adjustStatusBarLocked();
+ mDismissCallbackRegistry.notifyDismissSucceeded();
sendUserPresentBroadcast();
}
Trace.endSection();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 0c2c5bc..4feaf5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -62,6 +62,7 @@
private int mAppUid;
private List<NotificationChannel> mNotificationChannels;
private NotificationChannel mSingleNotificationChannel;
+ private boolean mIsSingleDefaultChannel;
private StatusBarNotification mSbn;
private int mStartingUserImportance;
@@ -113,17 +114,23 @@
mSbn = sbn;
mPm = pm;
mAppSettingsClickListener = onAppSettingsClick;
- boolean isSingleDefaultChannel = false;
mStartingUserImportance = startingUserImportance;
+ int numTotalChannels = 1;
+ numTotalChannels = iNotificationManager.getNumNotificationChannelsForPackage(
+ pkg, mAppUid, false /* includeDeleted */);
if (mNotificationChannels.isEmpty()) {
throw new IllegalArgumentException("bindNotification requires at least one channel");
} else {
if (mNotificationChannels.size() == 1) {
mSingleNotificationChannel = mNotificationChannels.get(0);
- isSingleDefaultChannel = mSingleNotificationChannel.getId()
- .equals(NotificationChannel.DEFAULT_CHANNEL_ID);
+ // Special behavior for the Default channel if no other channels have been defined.
+ mIsSingleDefaultChannel =
+ (mSingleNotificationChannel.getId()
+ .equals(NotificationChannel.DEFAULT_CHANNEL_ID) &&
+ numTotalChannels <= 1);
} else {
mSingleNotificationChannel = null;
+ mIsSingleDefaultChannel = false;
}
}
@@ -148,19 +155,16 @@
}
((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
- int numChannels = 1;
- numChannels = iNotificationManager.getNumNotificationChannelsForPackage(
- pkg, mAppUid, false /* includeDeleted */);
-
String channelsDescText;
mNumChannelsView = findViewById(R.id.num_channels_desc);
- if (isSingleDefaultChannel) {
+ if (mIsSingleDefaultChannel) {
channelsDescText = mContext.getString(R.string.notification_default_channel_desc);
} else {
switch (mNotificationChannels.size()) {
case 1:
channelsDescText = String.format(mContext.getResources().getQuantityString(
- R.plurals.notification_num_channels_desc, numChannels), numChannels);
+ R.plurals.notification_num_channels_desc, numTotalChannels),
+ numTotalChannels);
break;
case 2:
channelsDescText = mContext.getString(
@@ -185,7 +189,7 @@
// Multiple channels don't use a channel name for the title.
channelNameText = mContext.getString(R.string.notification_num_channels,
mNotificationChannels.size());
- } else if (isSingleDefaultChannel) {
+ } else if (mIsSingleDefaultChannel) {
// If this is the default channel, don't use our channel-specific text.
channelNameText = mContext.getString(R.string.notification_header_default_channel);
} else {
@@ -241,7 +245,7 @@
(View view) -> {
onSettingsClick.onClick(view, mSingleNotificationChannel, appUidF);
});
- if (numChannels > 1) {
+ if (numTotalChannels > 1) {
settingsButton.setText(R.string.notification_all_categories);
} else {
settingsButton.setText(R.string.notification_more_settings);
@@ -327,14 +331,12 @@
private void updateSecondaryText() {
final boolean disabled = mSingleNotificationChannel != null &&
getSelectedImportance() == IMPORTANCE_NONE;
- final boolean isDefaultChannel = mSingleNotificationChannel != null &&
- mSingleNotificationChannel.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID);
if (disabled) {
mChannelDisabledView.setVisibility(View.VISIBLE);
mNumChannelsView.setVisibility(View.GONE);
} else {
mChannelDisabledView.setVisibility(View.GONE);
- mNumChannelsView.setVisibility(isDefaultChannel ? View.INVISIBLE : View.VISIBLE);
+ mNumChannelsView.setVisibility(mIsSingleDefaultChannel ? View.INVISIBLE : View.VISIBLE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index fcb7289..efbf76b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -17,7 +17,10 @@
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -28,16 +31,23 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.os.AsyncTask;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
+import android.security.KeyChain;
+import android.security.KeyChain.KeyChainConnection;
+import android.util.ArrayMap;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.settings.CurrentUserTracker;
@@ -59,6 +69,8 @@
private static final String VPN_BRANDED_META_DATA = "com.android.systemui.IS_BRANDED";
+ private static final int CA_CERT_LOADING_RETRY_TIME_IN_MS = 30_000;
+
private final Context mContext;
private final ConnectivityManager mConnectivityManager;
private final IConnectivityManager mConnectivityManagerService;
@@ -73,6 +85,10 @@
private int mCurrentUserId;
private int mVpnUserId;
+ // Key: userId, Value: whether the user has CACerts installed
+ // Needs to be cached here since the query has to be asynchronous
+ private ArrayMap<Integer, Boolean> mHasCACerts = new ArrayMap<Integer, Boolean>();
+
public SecurityControllerImpl(Context context) {
super(context);
mContext = context;
@@ -86,6 +102,11 @@
mUserManager = (UserManager)
context.getSystemService(Context.USER_SERVICE);
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(KeyChain.ACTION_TRUST_STORE_CHANGED);
+ context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null,
+ new Handler(Dependency.get(Dependency.BG_LOOPER)));
+
// TODO: re-register network callback on user change.
mConnectivityManager.registerNetworkCallback(REQUEST, mNetworkCallback);
onUserSwitched(ActivityManager.getCurrentUser());
@@ -218,14 +239,16 @@
@Override
public boolean hasCACertInCurrentUser() {
- //TODO: implement
- return false;
+ Boolean hasCACerts = mHasCACerts.get(mCurrentUserId);
+ return hasCACerts != null && hasCACerts.booleanValue();
}
@Override
public boolean hasCACertInWorkProfile() {
- //TODO: implement
- return false;
+ int userId = getWorkProfileUserId(mCurrentUserId);
+ if (userId == UserHandle.USER_NULL) return false;
+ Boolean hasCACerts = mHasCACerts.get(userId);
+ return hasCACerts != null && hasCACerts.booleanValue();
}
@Override
@@ -256,9 +279,16 @@
} else {
mVpnUserId = mCurrentUserId;
}
+ refreshCACerts();
fireCallbacks();
}
+ private void refreshCACerts() {
+ new CACertLoader().execute(mCurrentUserId);
+ int workProfileId = getWorkProfileUserId(mCurrentUserId);
+ if (workProfileId != UserHandle.USER_NULL) new CACertLoader().execute(workProfileId);
+ }
+
private String getNameForVpnConfig(VpnConfig cfg, UserHandle user) {
if (cfg.legacy) {
return mContext.getString(R.string.legacy_vpn_name);
@@ -348,4 +378,39 @@
fireCallbacks();
};
};
+
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override public void onReceive(Context context, Intent intent) {
+ if (KeyChain.ACTION_TRUST_STORE_CHANGED.equals(intent.getAction())) {
+ refreshCACerts();
+ }
+ }
+ };
+
+ protected class CACertLoader extends AsyncTask<Integer, Void, Pair<Integer, Boolean> > {
+
+ @Override
+ protected Pair<Integer, Boolean> doInBackground(Integer... userId) {
+ try (KeyChainConnection conn = KeyChain.bindAsUser(mContext,
+ UserHandle.of(userId[0]))) {
+ boolean hasCACerts = !(conn.getService().getUserCaAliases().getList().isEmpty());
+ return new Pair<Integer, Boolean>(userId[0], hasCACerts);
+ } catch (RemoteException | InterruptedException | AssertionError e) {
+ Log.i(TAG, e.getMessage());
+ new Handler(Dependency.get(Dependency.BG_LOOPER)).postDelayed(
+ () -> new CACertLoader().execute(userId[0]),
+ CA_CERT_LOADING_RETRY_TIME_IN_MS);
+ return new Pair<Integer, Boolean>(userId[0], null);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Pair<Integer, Boolean> result) {
+ if (DEBUG) Log.d(TAG, "onPostExecute " + result);
+ if (result.second != null) {
+ mHasCACerts.put(result.first, result.second);
+ fireCallbacks();
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index e7bce708..df2be48 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -19,9 +19,11 @@
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
+import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.Preference;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -43,6 +45,11 @@
public static final String SETTING_SEEN_TUNER_WARNING = "seen_tuner_warning";
private static final String WARNING_TAG = "tuner_warning";
+ private static final String[] DEBUG_ONLY = new String[] {
+ "nav_bar",
+ "lockscreen",
+ "picture_in_picture",
+ };
private static final int MENU_REMOVE = Menu.FIRST + 1;
@@ -68,6 +75,12 @@
if (!alwaysOnAvailable()) {
getPreferenceScreen().removePreference(findPreference(KEY_DOZE));
}
+ if (!Build.IS_DEBUGGABLE) {
+ for (int i = 0; i < DEBUG_ONLY.length; i++) {
+ Preference preference = findPreference(DEBUG_ONLY[i]);
+ if (preference != null) getPreferenceScreen().removePreference(preference);
+ }
+ }
if (Settings.Secure.getInt(getContext().getContentResolver(), SETTING_SEEN_TUNER_WARNING,
0) == 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index b8b046b..8d8931f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -642,7 +642,6 @@
updateVolumeRowSliderTintH(row, isActive);
}
}
-
}
private void trimObsoleteH() {
@@ -695,28 +694,25 @@
final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF
&& (mAudioManager.isStreamAffectedByRingerMode(mActiveStream) || mExpanded)
&& !mZenPanel.isEditing();
- TransitionManager.beginDelayedTransition(mDialogView, getTransistion());
- if (wasVisible != visible && !visible) {
- prepareForCollapse();
+
+ if (wasVisible != visible) {
+ mZenFooter.update();
+ Util.setVisOrGone(mZenFooter, visible);
}
- Util.setVisOrGone(mZenFooter, visible);
- mZenFooter.update();
final boolean fullWasVisible = mZenPanel.getVisibility() == View.VISIBLE;
final boolean fullVisible = mShowFullZen && !visible;
- if (fullWasVisible != fullVisible && !fullVisible) {
- prepareForCollapse();
- }
- Util.setVisOrGone(mZenPanel, fullVisible);
- if (fullVisible) {
- mZenPanel.setZenState(mState.zenMode);
- mZenPanel.setDoneListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- prepareForCollapse();
- mHandler.sendEmptyMessage(H.UPDATE_FOOTER);
- }
- });
+ if (fullWasVisible != fullVisible) {
+ Util.setVisOrGone(mZenPanel, fullVisible);
+ if (fullVisible) {
+ mZenPanel.setZenState(mState.zenMode);
+ mZenPanel.setDoneListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mHandler.sendEmptyMessage(H.UPDATE_FOOTER);
+ }
+ });
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
index 10b6ff5..17d98b1 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
@@ -20,12 +20,16 @@
import android.content.Context;
import android.provider.Settings.Global;
import android.service.notification.ZenModeConfig;
+import android.transition.AutoTransition;
+import android.transition.TransitionManager;
import android.util.AttributeSet;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -44,6 +48,9 @@
private TextView mSummaryLine1;
private TextView mSummaryLine2;
private TextView mEndNowButton;
+ private View mZenIntroduction;
+ private View mZenIntroductionConfirm;
+ private TextView mZenIntroductionMessage;
private int mZen = -1;
private ZenModeConfig mConfig;
private ZenModeController mController;
@@ -64,6 +71,17 @@
mSummaryLine1 = findViewById(R.id.volume_zen_summary_line_1);
mSummaryLine2 = findViewById(R.id.volume_zen_summary_line_2);
mEndNowButton = findViewById(R.id.volume_zen_end_now);
+ mZenIntroduction = findViewById(R.id.zen_introduction);
+ mZenIntroductionMessage = findViewById(R.id.zen_introduction_message);
+ mConfigurableTexts.add(mZenIntroductionMessage, R.string.zen_alarms_introduction);
+ mZenIntroductionConfirm = findViewById(R.id.zen_introduction_confirm);
+ mZenIntroductionConfirm.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ confirmZenIntroduction();
+ }
+ });
+ Util.setVisOrGone(mZenIntroduction, shouldShowIntroduction());
mConfigurableTexts.add(mSummaryLine1);
mConfigurableTexts.add(mSummaryLine2);
mConfigurableTexts.add(mEndNowButton, R.string.volume_zen_end_now);
@@ -73,6 +91,7 @@
mEndNowButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
+ setZen(Global.ZEN_MODE_OFF);
controller.setZen(Global.ZEN_MODE_OFF, null, TAG);
}
});
@@ -81,6 +100,7 @@
mController = controller;
mController.addCallback(mZenCallback);
update();
+ updateIntroduction();
}
public void cleanup() {
@@ -91,6 +111,7 @@
if (mZen == zen) return;
mZen = zen;
update();
+ updateIntroduction();
}
private void setConfig(ZenModeConfig config) {
@@ -99,8 +120,9 @@
update();
}
- public boolean isZen() {
- return isZenPriority() || isZenAlarms() || isZenNone();
+ private void confirmZenIntroduction() {
+ Prefs.putBoolean(mContext, Prefs.Key.DND_CONFIRMED_ALARM_INTRODUCTION, true);
+ updateIntroduction();
}
private boolean isZenPriority() {
@@ -128,6 +150,15 @@
mController.getCurrentUser(), true /*shortVersion*/);
Util.setText(mSummaryLine2, line2);
}
+ public boolean shouldShowIntroduction() {
+ final boolean confirmed = Prefs.getBoolean(mContext,
+ Prefs.Key.DND_CONFIRMED_ALARM_INTRODUCTION, false);
+ return !confirmed && isZenAlarms();
+ }
+
+ public void updateIntroduction() {
+ Util.setVisOrGone(mZenIntroduction, shouldShowIntroduction());
+ }
public void onConfigurationChanged() {
mConfigurableTexts.update();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index fffcc08..51fcdbb 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -284,6 +284,8 @@
return Prefs.Key.DND_CONFIRMED_PRIORITY_INTRODUCTION;
case Global.ZEN_MODE_NO_INTERRUPTIONS:
return Prefs.Key.DND_CONFIRMED_SILENCE_INTRODUCTION;
+ case Global.ZEN_MODE_ALARMS:
+ return Prefs.Key.DND_CONFIRMED_ALARM_INTRODUCTION;
default:
return null;
}
@@ -523,16 +525,22 @@
final int zen = getSelectedZen(Global.ZEN_MODE_OFF);
final boolean zenImportant = zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS;
+ final boolean zenAlarm = zen == Global.ZEN_MODE_ALARMS;
final boolean introduction = (zenImportant && !mPrefs.mConfirmedPriorityIntroduction
- || zenNone && !mPrefs.mConfirmedSilenceIntroduction);
+ || zenNone && !mPrefs.mConfirmedSilenceIntroduction
+ || zenAlarm && !mPrefs.mConfirmedAlarmIntroduction);
mZenButtons.setVisibility(mHidden ? GONE : VISIBLE);
mZenIntroduction.setVisibility(introduction ? VISIBLE : GONE);
if (introduction) {
- mConfigurableTexts.add(mZenIntroductionMessage, zenImportant
+ int message = zenImportant
? R.string.zen_priority_introduction
- : mVoiceCapable ? R.string.zen_silence_introduction_voice
- : R.string.zen_silence_introduction);
+ : zenAlarm
+ ? R.string.zen_alarms_introduction
+ : mVoiceCapable
+ ? R.string.zen_silence_introduction_voice
+ : R.string.zen_silence_introduction;
+ mConfigurableTexts.add(mZenIntroductionMessage, message);
mConfigurableTexts.update();
mZenIntroductionCustomize.setVisibility(zenImportant ? VISIBLE : GONE);
}
@@ -963,6 +971,7 @@
private int mNoneSelected;
private boolean mConfirmedPriorityIntroduction;
private boolean mConfirmedSilenceIntroduction;
+ private boolean mConfirmedAlarmIntroduction;
private ZenPrefs() {
mNoneDangerousThreshold = mContext.getResources()
@@ -972,6 +981,7 @@
updateNoneSelected();
updateConfirmedPriorityIntroduction();
updateConfirmedSilenceIntroduction();
+ updateConfirmedAlarmIntroduction();
}
public void trackNoneSelected() {
@@ -999,6 +1009,7 @@
updateNoneSelected();
updateConfirmedPriorityIntroduction();
updateConfirmedSilenceIntroduction();
+ updateConfirmedAlarmIntroduction();
}
private void updateMinuteIndex() {
@@ -1038,6 +1049,15 @@
if (DEBUG) Log.d(mTag, "Confirmed silence introduction: "
+ mConfirmedSilenceIntroduction);
}
+
+ private void updateConfirmedAlarmIntroduction() {
+ final boolean confirmed = Prefs.getBoolean(mContext,
+ Prefs.Key.DND_CONFIRMED_ALARM_INTRODUCTION, false);
+ if (confirmed == mConfirmedAlarmIntroduction) return;
+ mConfirmedAlarmIntroduction = confirmed;
+ if (DEBUG) Log.d(mTag, "Confirmed alarm introduction: "
+ + mConfirmedAlarmIntroduction);
+ }
}
protected final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index 0531ec5..0118a80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -210,6 +210,30 @@
}
@Test
+ public void testBindNotification_DefaultChannelDoesNotUseChannelName() throws Exception {
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel),
+ mNotificationChannel.getImportance(), mSbn, null, null, null,
+ null, null);
+ final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name);
+ assertEquals(mContext.getString(R.string.notification_header_default_channel),
+ textView.getText());
+ }
+
+ @Test
+ public void testBindNotification_DefaultChannelUsesNameWhenMoreThanOneChannelExists()
+ throws Exception {
+ when(mMockINotificationManager.getNumNotificationChannelsForPackage(
+ eq(TEST_PACKAGE_NAME), anyInt(), anyBoolean())).thenReturn(2);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel),
+ mNotificationChannel.getImportance(), mSbn, null, null, null,
+ null, null);
+ final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name);
+ assertEquals(mDefaultNotificationChannel.getName(), textView.getText());
+ }
+
+ @Test
public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
@@ -325,6 +349,21 @@
}
@Test
+ public void testBindNotification_NumChannelsTextDisplaysWhenMoreThanOneChannelExists()
+ throws Exception {
+ when(mMockINotificationManager.getNumNotificationChannelsForPackage(
+ eq(TEST_PACKAGE_NAME), anyInt(), anyBoolean())).thenReturn(2);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel),
+ mNotificationChannel.getImportance(), mSbn, null, null,
+ null, null, null);
+ final TextView numChannelsView =
+ (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
+ assertEquals(numChannelsView.getVisibility(), View.VISIBLE);
+ assertEquals(getNumChannelsDescString(2), numChannelsView.getText());
+ }
+
+ @Test
public void testBindNotification_NumChannelsTextDisplaysWhenNotDefaultChannel()
throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
index 87c4c66..ae0509a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
@@ -21,31 +21,76 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.doNothing;
import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.StringParceledListSlice;
import android.net.ConnectivityManager;
+import android.security.IKeyChainService;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.systemui.statusbar.policy.SecurityController.SecurityControllerCallback;
import com.android.systemui.SysuiTestCase;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.List;
+
+import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class SecurityControllerTest extends SysuiTestCase {
+public class SecurityControllerTest extends SysuiTestCase implements SecurityControllerCallback {
private final DevicePolicyManager mDevicePolicyManager = mock(DevicePolicyManager.class);
+ private final IKeyChainService.Stub mKeyChainService = mock(IKeyChainService.Stub.class);
private SecurityControllerImpl mSecurityController;
+ private CountDownLatch mStateChangedLatch;
+
+ // implementing SecurityControllerCallback
+ @Override
+ public void onStateChanged() {
+ mStateChangedLatch.countDown();
+ }
@Before
public void setUp() throws Exception {
mContext.addMockSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager);
mContext.addMockSystemService(Context.CONNECTIVITY_SERVICE, mock(ConnectivityManager.class));
+
+ Intent intent = new Intent(IKeyChainService.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ mContext.addMockService(comp, mKeyChainService);
+
+ when(mKeyChainService.getUserCaAliases())
+ .thenReturn(new StringParceledListSlice(new ArrayList<String>()));
+ // Without this line, mKeyChainService gets wrapped in a proxy when Stub.asInterface() is
+ // used on it, and the mocking above does not work.
+ when(mKeyChainService.queryLocalInterface("android.security.IKeyChainService"))
+ .thenReturn(mKeyChainService);
+
mSecurityController = new SecurityControllerImpl(mContext);
+
+ // Wait for one or two state changes from the CACertLoader(s) in the constructor of
+ // mSecurityController
+ mStateChangedLatch = new CountDownLatch(mSecurityController.hasWorkProfile() ? 2 : 1);
+ mSecurityController.addCallback(this);
+ }
+
+ @After
+ public void tearDown() {
+ mSecurityController.removeCallback(this);
}
@Test
@@ -62,4 +107,41 @@
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn("organization");
assertEquals("organization", mSecurityController.getDeviceOwnerOrganizationName());
}
+
+ @Test
+ @Ignore("Flaky")
+ public void testCaCertLoader() throws Exception {
+ assertTrue(mStateChangedLatch.await(3, TimeUnit.SECONDS));
+ assertFalse(mSecurityController.hasCACertInCurrentUser());
+
+ // With a CA cert
+
+ mStateChangedLatch = new CountDownLatch(1);
+
+ when(mKeyChainService.getUserCaAliases())
+ .thenReturn(new StringParceledListSlice(Arrays.asList("One CA Alias")));
+
+ mSecurityController.new CACertLoader()
+ .execute(0);
+
+ assertTrue(mStateChangedLatch.await(3, TimeUnit.SECONDS));
+ assertTrue(mSecurityController.hasCACertInCurrentUser());
+
+ // Exception
+
+ mStateChangedLatch = new CountDownLatch(1);
+
+ when(mKeyChainService.getUserCaAliases())
+ .thenThrow(new AssertionError("Test AssertionError"))
+ .thenReturn(new StringParceledListSlice(new ArrayList<String>()));
+
+ mSecurityController.new CACertLoader()
+ .execute(0);
+
+ assertFalse(mStateChangedLatch.await(3, TimeUnit.SECONDS));
+ assertTrue(mSecurityController.hasCACertInCurrentUser());
+ // The retry takes 30s
+ //assertTrue(mStateChangedLatch.await(31, TimeUnit.SECONDS));
+ //assertFalse(mSecurityController.hasCACertInCurrentUser());
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index a5cfbcf..5c57be2 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -131,6 +131,7 @@
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
+import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
@@ -892,15 +893,7 @@
Entry ent = AttributeCache.instance().get(packageName,
realTheme, com.android.internal.R.styleable.Window, userId);
- final boolean translucent = ent != null && (ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowIsTranslucent, false)
- || (!ent.array.hasValue(
- com.android.internal.R.styleable.Window_windowIsTranslucent)
- && ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowSwipeToDismiss,
- false)));
- fullscreen = ent != null && !ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowIsFloating, false) && !translucent;
+ fullscreen = ent != null && !ActivityInfo.isTranslucentOrFloating(ent.array);
noDisplay = ent != null && ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowNoDisplay, false);
@@ -2186,6 +2179,11 @@
}
void setRequestedOrientation(int requestedOrientation) {
+ if (ActivityInfo.isFixedOrientation(requestedOrientation) && !fullscreen
+ && appInfo.targetSdkVersion >= O) {
+ throw new IllegalStateException("Only fullscreen activities can request orientation");
+ }
+
final int displayId = getDisplayId();
final Configuration displayConfig =
mStackSupervisor.getDisplayOverrideConfiguration(displayId);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index e33ae0d..6d4eb5b 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -637,7 +637,6 @@
if (componentSpecified
&& intent.getData() != null
&& Intent.ACTION_VIEW.equals(intent.getAction())
- && intent.hasCategory(Intent.CATEGORY_BROWSABLE)
&& mService.getPackageManagerInternalLocked()
.isInstantAppInstallerComponent(intent.getComponent())) {
// intercept intents targeted directly to the ephemeral installer the
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 70766f9..23a1a78 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -96,6 +96,7 @@
import android.media.AudioManager;
import android.media.AudioManagerInternal;
import android.media.IRingtonePlayer;
+import android.media.ToneGenerator;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -301,6 +302,10 @@
private boolean mInCall = false;
private boolean mNotificationPulseEnabled;
+ // for generating notification tones in-call
+ private ToneGenerator mInCallToneGenerator;
+ private final Object mInCallToneGeneratorLock = new Object();
+
// used as a mutex for access to all active notifications & listeners
final Object mNotificationLock = new Object();
final ArrayList<NotificationRecord> mNotificationList =
@@ -854,6 +859,30 @@
mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
.equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
updateNotificationPulse();
+ synchronized (mInCallToneGeneratorLock) {
+ if (mInCall) {
+ if (mInCallToneGenerator == null) {
+ int relativeToneVolume = getContext().getResources().getInteger(
+ R.integer.config_inCallNotificationVolumeRelative);
+ if (relativeToneVolume < ToneGenerator.MIN_VOLUME
+ || relativeToneVolume > ToneGenerator.MAX_VOLUME) {
+ relativeToneVolume = ToneGenerator.MAX_VOLUME;
+ }
+ try {
+ mInCallToneGenerator = new ToneGenerator(
+ AudioManager.STREAM_VOICE_CALL, relativeToneVolume);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Error creating local tone generator: " + e);
+ mInCallToneGenerator = null;
+ }
+ }
+ } else {
+ if (mInCallToneGenerator != null) {
+ mInCallToneGenerator.release();
+ mInCallToneGenerator = null;
+ }
+ }
+ }
} else if (action.equals(Intent.ACTION_USER_STOPPED)) {
int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (userHandle >= 0) {
@@ -3723,14 +3752,21 @@
hasValidVibrate = vibration != null;
if (!shouldMuteNotificationLocked(record)) {
-
sendAccessibilityEvent(notification, record.sbn.getPackageName());
+
if (hasValidSound) {
mSoundNotificationKey = key;
- beep = playSound(record, soundUri);
+ if (mInCall) {
+ playInCallNotification();
+ beep = true;
+ } else {
+ beep = playSound(record, soundUri);
+ }
}
- if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
- == AudioManager.RINGER_MODE_SILENT)) {
+
+ final boolean ringerModeSilent =
+ mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT;
+ if (!mInCall && hasValidVibrate && !ringerModeSilent) {
mVibrateNotificationKey = key;
buzz = playVibration(record, vibration);
@@ -3839,6 +3875,26 @@
}
}
+ private void playInCallNotification() {
+ new Thread() {
+ @Override
+ public void run() {
+ // If toneGenerator creation fails, just continue the call
+ // without playing the notification sound.
+ try {
+ synchronized (mInCallToneGeneratorLock) {
+ if (mInCallToneGenerator != null) {
+ // limit this tone to 1 second; BEEP2 should in fact be much shorter
+ mInCallToneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP2, 1000);
+ }
+ }
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Exception from ToneGenerator: " + e);
+ }
+ }
+ }.start();
+ }
+
void showNextToastLocked() {
ToastRecord record = mToastQueue.get(0);
while (record != null) {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 2e4b49a..271045a 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -316,6 +316,7 @@
if (arg == null) {
builder.append('!');
+ return;
}
String txt = String.valueOf(arg);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f2cdaa9..f1e4e12 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4218,7 +4218,6 @@
final boolean allowMatchInstant =
(includeInstantApps
&& Intent.ACTION_VIEW.equals(intent.getAction())
- && intent.hasCategory(Intent.CATEGORY_BROWSABLE)
&& hasWebURI(intent))
|| isSpecialProcess
|| mContext.checkCallingOrSelfPermission(
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 640bac2..982561c 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -53,6 +53,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
+import android.os.Build;
import android.os.Debug;
import android.os.IBinder;
import android.os.SystemClock;
@@ -70,6 +71,8 @@
import java.util.ArrayDeque;
import java.util.ArrayList;
+import static android.os.Build.VERSION_CODES.O;
+
class AppTokenList extends ArrayList<AppWindowToken> {
}
@@ -1245,7 +1248,11 @@
*/
@Override
int getOrientation(int candidate) {
- if (!fillsParent()) {
+ // We do not allow non-fullscreen apps to influence orientation at and beyond O. While we do
+ // throw an exception in {@link Activity#onCreate} and
+ // {@link Activity#setRequestedOrientation}, we also ignore the orientation here so that
+ // other calculations aren't affected.
+ if (!fillsParent() && mTargetSdk >= O) {
// Can't specify orientation if app doesn't fill parent.
return SCREEN_ORIENTATION_UNSET;
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 876008b..46f10c1 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -173,8 +173,8 @@
token.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
token.setFillsParent(false);
- // Can not specify orientation if app doesn't fill parent.
- assertEquals(SCREEN_ORIENTATION_UNSET, token.getOrientation());
+ // Can specify orientation if app doesn't fill parent. Allowed for SDK <= 25.
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, token.getOrientation());
token.setFillsParent(true);
token.hidden = true;