Merge "Using Message.obtain() to decrease number of Messages allocated." into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 44df333..fec8b06 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2666,6 +2666,7 @@
field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6
field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5
field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3
+ field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7
field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
}
@@ -19172,7 +19173,6 @@
method public short getLeapSecond();
method public long getTimeInNs();
method public double getTimeUncertaintyInNs();
- method public byte getType();
method public boolean hasBiasInNs();
method public boolean hasBiasUncertaintyInNs();
method public boolean hasDriftInNsPerSec();
@@ -19198,17 +19198,10 @@
method public void setLeapSecond(short);
method public void setTimeInNs(long);
method public void setTimeUncertaintyInNs(double);
- method public void setType(byte);
method public void writeToParcel(android.os.Parcel, int);
- field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2
- field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1
- field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0
field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
}
- public static abstract class GnssClock.GnssClockType implements java.lang.annotation.Annotation {
- }
-
public final class GnssMeasurement implements android.os.Parcelable {
method public int describeContents();
method public double getAccumulatedDeltaRangeInMeters();
@@ -19774,6 +19767,7 @@
field public static final int ENCODING_PCM_16BIT = 2; // 0x2
field public static final int ENCODING_PCM_8BIT = 3; // 0x3
field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
+ field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0
}
public static class AudioFormat.Builder {
@@ -44085,6 +44079,7 @@
field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
field public static final int TYPE_APPLICATION = 1; // 0x1
field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+ field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
field public static final int TYPE_SYSTEM = 3; // 0x3
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 79d0cd7..b088f83 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2768,6 +2768,7 @@
field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6
field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5
field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3
+ field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7
field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
}
@@ -20361,7 +20362,6 @@
method public short getLeapSecond();
method public long getTimeInNs();
method public double getTimeUncertaintyInNs();
- method public byte getType();
method public boolean hasBiasInNs();
method public boolean hasBiasUncertaintyInNs();
method public boolean hasDriftInNsPerSec();
@@ -20387,17 +20387,10 @@
method public void setLeapSecond(short);
method public void setTimeInNs(long);
method public void setTimeUncertaintyInNs(double);
- method public void setType(byte);
method public void writeToParcel(android.os.Parcel, int);
- field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2
- field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1
- field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0
field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
}
- public static abstract class GnssClock.GnssClockType implements java.lang.annotation.Annotation {
- }
-
public final class GnssMeasurement implements android.os.Parcelable {
method public int describeContents();
method public double getAccumulatedDeltaRangeInMeters();
@@ -21270,6 +21263,7 @@
field public static final int ENCODING_PCM_16BIT = 2; // 0x2
field public static final int ENCODING_PCM_8BIT = 3; // 0x3
field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
+ field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0
}
public static class AudioFormat.Builder {
@@ -46869,6 +46863,7 @@
field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
field public static final int TYPE_APPLICATION = 1; // 0x1
field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+ field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
field public static final int TYPE_SYSTEM = 3; // 0x3
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 4b62e28..006dec4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2666,6 +2666,7 @@
field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6
field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5
field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3
+ field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7
field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
}
@@ -19180,7 +19181,6 @@
method public short getLeapSecond();
method public long getTimeInNs();
method public double getTimeUncertaintyInNs();
- method public byte getType();
method public boolean hasBiasInNs();
method public boolean hasBiasUncertaintyInNs();
method public boolean hasDriftInNsPerSec();
@@ -19206,17 +19206,10 @@
method public void setLeapSecond(short);
method public void setTimeInNs(long);
method public void setTimeUncertaintyInNs(double);
- method public void setType(byte);
method public void writeToParcel(android.os.Parcel, int);
- field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2
- field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1
- field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0
field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
}
- public static abstract class GnssClock.GnssClockType implements java.lang.annotation.Annotation {
- }
-
public final class GnssMeasurement implements android.os.Parcelable {
method public int describeContents();
method public double getAccumulatedDeltaRangeInMeters();
@@ -19783,6 +19776,7 @@
field public static final int ENCODING_PCM_16BIT = 2; // 0x2
field public static final int ENCODING_PCM_8BIT = 3; // 0x3
field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
+ field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0
}
public static class AudioFormat.Builder {
@@ -44102,6 +44096,7 @@
field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
field public static final int TYPE_APPLICATION = 1; // 0x1
field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+ field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
field public static final int TYPE_SYSTEM = 3; // 0x3
}
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 24449d4..4025553 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1490,7 +1490,7 @@
System.err.println(" -i: specify the installer package name");
System.err.println(" -s: install application on sdcard");
System.err.println(" -f: install application on internal flash");
- System.err.println(" -d: allow version code downgrade");
+ System.err.println(" -d: allow version code downgrade (debuggable packages only)");
System.err.println(" -p: partial application install");
System.err.println(" -g: grant all runtime permissions");
System.err.println(" -S: size in bytes of entire session");
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 4bc6b97..fb5f5b9 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -334,7 +334,7 @@
public static final int GLOBAL_ACTION_HOME = 2;
/**
- * Action to open the recent apps.
+ * Action to toggle showing the overview of recent apps
*/
public static final int GLOBAL_ACTION_RECENTS = 3;
@@ -353,6 +353,11 @@
*/
public static final int GLOBAL_ACTION_POWER_DIALOG = 6;
+ /**
+ * Action to toggle docking the current app's window
+ */
+ public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7;
+
private static final String LOG_TAG = "AccessibilityService";
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index eaff1ac..cb45deb 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -58,6 +58,7 @@
import android.util.AndroidException;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.LocaleList;
import android.util.Log;
import com.android.internal.util.ArrayUtils;
@@ -2071,6 +2072,8 @@
if (outConfig.fontScale < 0) {
outConfig.fontScale = 1;
}
+ outConfig.setLocales(LocaleList.forLanguageTags(
+ Settings.System.getStringForUser(cr, SYSTEM_LOCALES, userHandle)));
}
/**
@@ -2079,6 +2082,9 @@
*/
public static void clearConfiguration(Configuration inoutConfig) {
inoutConfig.fontScale = 0;
+ if (!inoutConfig.userSetLocale) {
+ inoutConfig.setLocales(LocaleList.getEmptyLocaleList());
+ }
}
/**
@@ -2096,12 +2102,15 @@
/** @hide */
public static boolean putConfigurationForUser(ContentResolver cr, Configuration config,
int userHandle) {
- return Settings.System.putFloatForUser(cr, FONT_SCALE, config.fontScale, userHandle);
+ return Settings.System.putFloatForUser(cr, FONT_SCALE, config.fontScale, userHandle) &&
+ Settings.System.putStringForUser(
+ cr, SYSTEM_LOCALES, config.getLocales().toLanguageTags(), userHandle);
}
/** @hide */
public static boolean hasInterestingConfigurationChanges(int changes) {
- return (changes&ActivityInfo.CONFIG_FONT_SCALE) != 0;
+ return (changes & ActivityInfo.CONFIG_FONT_SCALE) != 0 ||
+ (changes & ActivityInfo.CONFIG_LOCALE) != 0;
}
/** @deprecated - Do not use */
@@ -2480,6 +2489,18 @@
};
/**
+ * The serialized system locale value.
+ *
+ * Do not use this value directory.
+ * To get system locale, use {@link android.util.LocaleList#getDefault} instead.
+ * To update system locale, use {@link com.android.internal.app.LocalePicker#updateLocales}
+ * instead.
+ * @hide
+ */
+ public static final String SYSTEM_LOCALES = "system_locales";
+
+
+ /**
* Name of an application package to be debugged.
*
* @deprecated Use {@link Global#DEBUG_APP} instead
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 367c9fb..e79dfca 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -437,6 +437,7 @@
if (handled) {
adjustMetaAfterKeypress(content);
+ return true;
}
return super.onKeyDown(view, content, keyCode, event);
@@ -470,4 +471,3 @@
return true;
}
}
-
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index a75e8a7..ad78b68 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -64,6 +64,12 @@
*/
public static final int TYPE_ACCESSIBILITY_OVERLAY = 4;
+ /**
+ * Window type: A system window used to divide the screen in split-screen mode.
+ * This type of window is present only in split-screen mode.
+ */
+ public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5;
+
private static final int UNDEFINED = -1;
private static final int BOOLEAN_PROPERTY_ACTIVE = 1 << 0;
@@ -551,6 +557,9 @@
case TYPE_ACCESSIBILITY_OVERLAY: {
return "TYPE_ACCESSIBILITY_OVERLAY";
}
+ case TYPE_SPLIT_SCREEN_DIVIDER: {
+ return "TYPE_SPLIT_SCREEN_DIVIDER";
+ }
default:
return "<UNKNOWN>";
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 4c81d1a..54b3932 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1632,7 +1632,6 @@
final PopupDecorView decorView = mDecorView;
final View contentView = mContentView;
- final OnDismissListener dismissListener = mOnDismissListener;
final ViewGroup contentHolder;
final ViewParent contentParent = contentView.getParent();
@@ -1676,16 +1675,19 @@
new TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
- dismissImmediate(decorView, contentHolder,
- contentView, dismissListener);
+ dismissImmediate(decorView, contentHolder, contentView);
}
});
} else {
- dismissImmediate(decorView, contentHolder, contentView, dismissListener);
+ dismissImmediate(decorView, contentHolder, contentView);
}
// Clears the anchor view.
unregisterForViewTreeChanges();
+
+ if (mOnDismissListener != null) {
+ mOnDismissListener.onDismiss();
+ }
}
/**
@@ -1727,8 +1729,7 @@
* Removes the popup from the window manager and tears down the supporting
* view hierarchy, if necessary.
*/
- private void dismissImmediate(View decorView, ViewGroup contentHolder,
- View contentView, OnDismissListener listener) {
+ private void dismissImmediate(View decorView, ViewGroup contentHolder, View contentView) {
// If this method gets called and the decor view doesn't have a parent,
// then it was either never added or was already removed. That should
// never happen, but it's worth checking to avoid potential crashes.
@@ -1745,10 +1746,6 @@
mDecorView = null;
mBackgroundView = null;
mIsTransitioningToDismiss = false;
-
- if (mOnDismissListener != null) {
- mOnDismissListener.onDismiss();
- }
}
/**
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index 6a365e0..b1b019c 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -275,7 +275,7 @@
config.setLocales(locales);
config.userSetLocale = true;
- am.updateConfiguration(config);
+ am.updatePersistentConfiguration(config);
// Trigger the dirty bit for the Settings Provider.
BackupManager.dataChanged("com.android.providers.settings");
} catch (RemoteException e) {
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 08d4fba..64c5b8d 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -60,6 +60,7 @@
void showRecentApps(boolean triggeredFromAltTab);
void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
void toggleRecentApps();
+ void toggleSplitScreen();
void preloadRecentApps();
void cancelPreloadRecentApps();
void showScreenPinningRequest();
diff --git a/core/java/com/android/internal/util/WakeupMessage.java b/core/java/com/android/internal/util/WakeupMessage.java
index 77859b8..451078b 100644
--- a/core/java/com/android/internal/util/WakeupMessage.java
+++ b/core/java/com/android/internal/util/WakeupMessage.java
@@ -21,7 +21,7 @@
import android.os.Handler;
import android.os.Message;
- /**
+/**
* An AlarmListener that sends the specified message to a Handler and keeps the system awake until
* the message is processed.
*
@@ -33,19 +33,17 @@
* the message, but does not guarantee that the system will be awake until the target object has
* processed it. This is because as soon as the onAlarmListener sends the message and returns, the
* AlarmManager releases its wakelock and the system is free to go to sleep again.
- *
*/
public class WakeupMessage implements AlarmManager.OnAlarmListener {
- private static AlarmManager sAlarmManager;
+ private final AlarmManager mAlarmManager;
private final Handler mHandler;
private final String mCmdName;
private final int mCmd, mArg1, mArg2;
+ private boolean mScheduled;
public WakeupMessage(Context context, Handler handler,
String cmdName, int cmd, int arg1, int arg2) {
- if (sAlarmManager == null) {
- sAlarmManager = context.getSystemService(AlarmManager.class);
- }
+ mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mHandler = handler;
mCmdName = cmdName;
mCmd = cmd;
@@ -61,19 +59,43 @@
this(context, handler, cmdName, cmd, 0, 0);
}
- public void schedule(long when) {
- sAlarmManager.setExact(
+ /**
+ * Schedule the message to be delivered at the time in milliseconds of the
+ * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()} clock and wakeup
+ * the device when it goes off. If schedule is called multiple times without the message being
+ * dispatched then the alarm is rescheduled to the new time.
+ */
+ public synchronized void schedule(long when) {
+ mAlarmManager.setExact(
AlarmManager.ELAPSED_REALTIME_WAKEUP, when, mCmdName, this, mHandler);
+ mScheduled = true;
}
- public void cancel() {
- sAlarmManager.cancel(this);
+ /**
+ * Cancel all pending messages. This includes alarms that may have been fired, but have not been
+ * run on the handler yet.
+ */
+ public synchronized void cancel() {
+ if (mScheduled) {
+ mAlarmManager.cancel(this);
+ mScheduled = false;
+ }
}
@Override
public void onAlarm() {
- Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2);
- mHandler.handleMessage(msg);
- msg.recycle();
+ // Once this method is called the alarm has already been fired and removed from
+ // AlarmManager (it is still partially tracked, but only for statistics). The alarm can now
+ // be marked as unscheduled so that it can be rescheduled in the message handler.
+ final boolean stillScheduled;
+ synchronized (this) {
+ stillScheduled = mScheduled;
+ mScheduled = false;
+ }
+ if (stillScheduled) {
+ Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2);
+ mHandler.handleMessage(msg);
+ msg.recycle();
+ }
}
}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 8b686b7..4be36594 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -7,7 +7,7 @@
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CFLAGS += -Wno-non-virtual-dtor
LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
-LOCAL_CFLAGS += -DHWUI_NEW_OPS
+#LOCAL_CFLAGS += -DHWUI_NEW_OPS
LOCAL_CPPFLAGS += -Wno-conversion-null
ifeq ($(TARGET_ARCH), arm)
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index d0326f1..6904fda 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -180,9 +180,13 @@
// ----------------------------------------------------------------------------
static jint
android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
- jobject jaa, jint sampleRateInHertz, jint channelMask, jint channelIndexMask,
+ jobject jaa, jintArray jSampleRate, jint channelMask, jint channelIndexMask,
jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName)
{
+ jint elements[1];
+ env->GetIntArrayRegion(jSampleRate, 0, 1, elements);
+ int sampleRateInHertz = elements[0];
+
//ALOGV(">> Entering android_media_AudioRecord_setup");
//ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d",
// sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes);
@@ -304,6 +308,11 @@
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL;
+ {
+ const jint elements[1] = { (jint) lpRecorder->getSampleRate() };
+ env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
+ }
+
{ // scope for the lock
Mutex::Autolock l(sLock);
sAudioRecordCallBackCookies.add(lpCallbackData);
@@ -717,7 +726,7 @@
// name, signature, funcPtr
{"native_start", "(II)I", (void *)android_media_AudioRecord_start},
{"native_stop", "()V", (void *)android_media_AudioRecord_stop},
- {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;IIIII[ILjava/lang/String;)I",
+ {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;)I",
(void *)android_media_AudioRecord_setup},
{"native_finalize", "()V", (void *)android_media_AudioRecord_finalize},
{"native_release", "()V", (void *)android_media_AudioRecord_release},
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 1ab9504..84cc185 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -215,9 +215,13 @@
static jint
android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
jobject jaa,
- jint sampleRateInHertz, jint channelPositionMask, jint channelIndexMask,
+ jintArray jSampleRate, jint channelPositionMask, jint channelIndexMask,
jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession) {
+ jint elements[1];
+ env->GetIntArrayRegion(jSampleRate, 0, 1, elements);
+ int sampleRateInHertz = elements[0];
+
ALOGV("sampleRate=%d, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d",
sampleRateInHertz, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes);
@@ -370,6 +374,11 @@
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL;
+ {
+ const jint elements[1] = { (jint) lpTrack->getSampleRate() };
+ env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
+ }
+
{ // scope for the lock
Mutex::Autolock l(sLock);
sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);
@@ -1114,7 +1123,7 @@
{"native_stop", "()V", (void *)android_media_AudioTrack_stop},
{"native_pause", "()V", (void *)android_media_AudioTrack_pause},
{"native_flush", "()V", (void *)android_media_AudioTrack_flush},
- {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;IIIIII[I)I",
+ {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[I)I",
(void *)android_media_AudioTrack_setup},
{"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
{"native_release", "()V", (void *)android_media_AudioTrack_release},
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index a3a3112..ae19150 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -25,7 +25,7 @@
<bool name="config_defaultWindowFeatureOptionsPanel">false</bool>
<!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. -->
- <string translatable="false" name="config_defaultPictureInPictureBounds">"1328 54 1808 324"</string>
+ <string translatable="false" name="config_defaultPictureInPictureBounds">"1420 100 1820 325"</string>
<!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows, when the PIP
is located in center. -->
@@ -34,5 +34,4 @@
<!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
when the PIP is shown with Recents. -->
<string translatable="false" name="config_pictureInPictureBoundsInRecents">"1480 123 1760 303"</string>
-
</resources>
diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk
index f949e1a..3c6c32e 100644
--- a/core/tests/utiltests/Android.mk
+++ b/core/tests/utiltests/Android.mk
@@ -12,7 +12,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-test
+ android-support-test \
+ mockito-target
LOCAL_JAVA_LIBRARIES := android.test.runner
diff --git a/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java b/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
new file mode 100644
index 0000000..da8bc1d
--- /dev/null
+++ b/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
@@ -0,0 +1,169 @@
+/*
+ * 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.internal.util;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+/**
+ * Unit tests for {@link com.android.internal.util.WakeupMessage}.
+ */
+@SmallTest
+public class WakeupMessageTest {
+ private static final String TEST_CMD_NAME = "TEST cmd Name";
+ private static final int TEST_CMD = 18;
+ private static final int TEST_ARG1 = 33;
+ private static final int TEST_ARG2 = 182;
+
+ @Mock AlarmManager mAlarmManager;
+ WakeupMessage mMessage;
+ // Make a spy so that we can verify calls to it
+ @Spy MessageCapturingHandler mHandler = new MessageCapturingHandler();
+
+ ArgumentCaptor<AlarmManager.OnAlarmListener> mListenerCaptor =
+ ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+
+ /**
+ * A Handler that will capture the most recent message sent to it.
+ *
+ * This handler is setup on the main Looper
+ */
+ public static class MessageCapturingHandler extends Handler {
+ private Message mLastMessage;
+
+ public MessageCapturingHandler() {
+ super(Looper.getMainLooper(), /* Nothing is actually dispatched on this Looper */
+ null, false);
+ }
+
+ @Override
+ public void handleMessage(Message m) {
+ // need to copy since it will be recycled after this method returns
+ mLastMessage = Message.obtain(m);
+ }
+
+ public Message getLastMessage() {
+ return mLastMessage;
+ }
+ }
+
+ /**
+ * Sets up the test.
+ */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ Context context = mock(Context.class);
+ when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
+ // capture the listener for each AlarmManager.setExact call
+ doNothing().when(mAlarmManager).setExact(anyInt(), anyLong(), any(String.class),
+ mListenerCaptor.capture(), any(Handler.class));
+
+ mMessage = new WakeupMessage(context, mHandler, TEST_CMD_NAME, TEST_CMD, TEST_ARG1,
+ TEST_ARG2);
+ }
+
+ /**
+ * Ensure the test is cleaned up and ready for the next test.
+ */
+ @After
+ public void cleanup() {
+ validateMockitoUsage();
+ }
+
+ private void scheduleAndVerifyAlarm(long when) {
+ mMessage.schedule(when);
+ verify(mAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(when),
+ eq(TEST_CMD_NAME), any(AlarmManager.OnAlarmListener.class), eq(mHandler));
+ }
+
+ private void verifyMessageDispatchedOnce() {
+ verify(mHandler, times(1)).handleMessage(any(Message.class));
+ assertEquals("what", TEST_CMD, mHandler.getLastMessage().what);
+ assertEquals("arg1", TEST_ARG1, mHandler.getLastMessage().arg1);
+ assertEquals("arg2", TEST_ARG2, mHandler.getLastMessage().arg2);
+ }
+
+ /**
+ * Schedule and deliver a single message
+ */
+ @Test
+ public void scheduleAndDeliverMessage() {
+ final long when = 1001;
+ scheduleAndVerifyAlarm(when);
+ verify(mHandler, never()).handleMessage(any(Message.class));
+ mListenerCaptor.getValue().onAlarm();
+ verifyMessageDispatchedOnce();
+ }
+
+ /**
+ * Check that the message is not delivered if cancel is called it after its alarm fires but
+ * before onAlarm is called.
+ *
+ * This ensures that if cancel is called on the handler thread, any previously-scheduled message
+ * is guaranteed not to be delivered.
+ */
+ @Test
+ public void scheduleAndCancelMessage() {
+ final long when = 1010;
+ scheduleAndVerifyAlarm(when);
+ mMessage.cancel();
+ mListenerCaptor.getValue().onAlarm();
+ verify(mHandler, never()).handleMessage(any(Message.class));
+ }
+
+ /**
+ * Verify nothing happens when cancel is called without a schedule
+ */
+ @Test
+ public void cancelWithoutSchedule() {
+ mMessage.cancel();
+ }
+
+ /**
+ * Verify that the message is silently rescheduled if schedule is called twice without the
+ * message being dispatched first.
+ */
+ @Test
+ public void scheduleTwiceWithoutMessageDispatched() {
+ final long when1 = 1011;
+ final long when2 = 1012;
+ scheduleAndVerifyAlarm(when1);
+ scheduleAndVerifyAlarm(when2);
+ mListenerCaptor.getValue().onAlarm();
+ verifyMessageDispatchedOnce();
+ }
+
+}
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index da7b7fb..8831baf 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -2,7 +2,7 @@
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-HWUI_NEW_OPS := true
+HWUI_NEW_OPS := false
# Enables fine-grained GLES error checking
# If set to true, every GLES call is wrapped & error checked
diff --git a/location/java/android/location/GnssClock.java b/location/java/android/location/GnssClock.java
index 5ba3f2c..3c8a78d 100644
--- a/location/java/android/location/GnssClock.java
+++ b/location/java/android/location/GnssClock.java
@@ -16,42 +16,16 @@
package android.location;
-import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
/**
* A class containing a GPS clock timestamp.
* It represents a measurement of the GPS receiver's clock.
*/
public final class GnssClock implements Parcelable {
-
// The following enumerations must be in sync with the values declared in gps.h
- /** The type of the GPS Clock. */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({CLOCK_TYPE_UNKNOWN, CLOCK_TYPE_LOCAL_HW_TIME, CLOCK_TYPE_GPS_TIME})
- public @interface GnssClockType {}
-
- /**
- * The type of the time stored is not available or it is unknown.
- */
- public static final byte CLOCK_TYPE_UNKNOWN = 0;
-
- /**
- * The source of the time value reported by this class is the 'Local Hardware Clock'.
- */
- public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1;
-
- /**
- * The source of the time value reported by this class is the 'GPS time' derived from
- * satellites (epoch = Jan 6, 1980).
- */
- public static final byte CLOCK_TYPE_GPS_TIME = 2;
-
private static final short HAS_NO_FLAGS = 0;
private static final short HAS_LEAP_SECOND = (1<<0);
private static final short HAS_TIME_UNCERTAINTY = (1<<1);
@@ -65,7 +39,6 @@
private short mFlags;
private short mLeapSecond;
- private byte mType;
private long mTimeInNs;
private double mTimeUncertaintyInNs;
private long mFullBiasInNs;
@@ -85,7 +58,6 @@
public void set(GnssClock clock) {
mFlags = clock.mFlags;
mLeapSecond = clock.mLeapSecond;
- mType = clock.mType;
mTimeInNs = clock.mTimeInNs;
mTimeUncertaintyInNs = clock.mTimeUncertaintyInNs;
mFullBiasInNs = clock.mFullBiasInNs;
@@ -104,38 +76,6 @@
}
/**
- * Gets the type of time reported by {@link #getTimeInNs()}.
- */
- @GnssClockType
- public byte getType() {
- return mType;
- }
-
- /**
- * Sets the type of time reported.
- */
- public void setType(@GnssClockType byte value) {
- mType = value;
- }
-
- /**
- * Gets a string representation of the 'type'.
- * For internal and logging use only.
- */
- private String getTypeString() {
- switch (mType) {
- case CLOCK_TYPE_UNKNOWN:
- return "Unknown";
- case CLOCK_TYPE_GPS_TIME:
- return "GpsTime";
- case CLOCK_TYPE_LOCAL_HW_TIME:
- return "LocalHwClock";
- default:
- return "<Invalid:" + mType + ">";
- }
- }
-
- /**
* Returns true if {@link #getLeapSecond()} is available, false otherwise.
*/
public boolean hasLeapSecond() {
@@ -170,10 +110,7 @@
}
/**
- * Gets the GPS receiver internal clock value in nanoseconds.
- * This can be either the 'local hardware clock' value ({@link #CLOCK_TYPE_LOCAL_HW_TIME}), or the
- * current GPS time derived inside GPS receiver ({@link #CLOCK_TYPE_GPS_TIME}).
- * {@link #getType()} defines the time reported.
+ * Gets the GNSS receiver internal clock value in nanoseconds.
*
* For 'local hardware clock' this value is expected to be monotonically increasing during the
* reporting session. The real GPS time can be derived by compensating
@@ -241,15 +178,14 @@
* Gets the difference between hardware clock ({@link #getTimeInNs()}) inside GPS receiver and
* the true GPS time since 0000Z, January 6, 1980, in nanoseconds.
*
- * This value is available if {@link #CLOCK_TYPE_LOCAL_HW_TIME} is set, and GPS receiver has solved
- * the clock for GPS time.
- * {@link #getBiasUncertaintyInNs()} should be used for quality check.
+ * This value is available if the receiver has estimated GPS time. If the computed time is for a
+ * non-GPS constellation, the time offset of that constellation to GPS has to be applied to fill
+ * this value. The value contains the 'bias uncertainty' {@link #getBiasUncertaintyInNs()} in
+ * it, and it should be used for quality check. The value is only available if
+ * {@link #hasFullBiasInNs()} is true.
*
* The sign of the value is defined by the following equation:
- * true time (GPS time) = time_ns + (full_bias_ns + bias_ns)
- *
- * The reported full bias includes {@link #getBiasUncertaintyInNs()}.
- * The value is onl available if {@link #hasFullBiasInNs()} is true.
+ * local estimate of GPS time = time_ns + (full_bias_ns + bias_ns)
*/
public long getFullBiasInNs() {
return mFullBiasInNs;
@@ -423,7 +359,6 @@
gpsClock.mFlags = (short) parcel.readInt();
gpsClock.mLeapSecond = (short) parcel.readInt();
- gpsClock.mType = parcel.readByte();
gpsClock.mTimeInNs = parcel.readLong();
gpsClock.mTimeUncertaintyInNs = parcel.readDouble();
gpsClock.mFullBiasInNs = parcel.readLong();
@@ -446,7 +381,6 @@
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mFlags);
parcel.writeInt(mLeapSecond);
- parcel.writeByte(mType);
parcel.writeLong(mTimeInNs);
parcel.writeDouble(mTimeUncertaintyInNs);
parcel.writeLong(mFullBiasInNs);
@@ -468,8 +402,6 @@
final String formatWithUncertainty = " %-15s = %-25s %-26s = %s\n";
StringBuilder builder = new StringBuilder("GnssClock:\n");
- builder.append(String.format(format, "Type", getTypeString()));
-
builder.append(String.format(format, "LeapSecond", hasLeapSecond() ? mLeapSecond : null));
builder.append(String.format(
@@ -498,17 +430,12 @@
"DriftUncertaintyInNsPerSec",
hasDriftUncertaintyInNsPerSec() ? mDriftUncertaintyInNsPerSec : null));
- builder.append(String.format(format, "HardwareClockDiscontinuityCount",
- getType() == CLOCK_TYPE_LOCAL_HW_TIME
- ? mHardwareClockDiscontinuityCount : null));
-
return builder.toString();
}
private void initialize() {
mFlags = HAS_NO_FLAGS;
resetLeapSecond();
- setType(CLOCK_TYPE_UNKNOWN);
setTimeInNs(Long.MIN_VALUE);
resetTimeUncertaintyInNs();
resetFullBiasInNs();
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index a619ab2..abdc13c 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -272,8 +272,9 @@
/**
* Gets the time offset at which the measurement was taken in nanoseconds.
- * The reference receiver's time is specified by {@link GnssClock#getTimeInNs()} and should be
- * interpreted in the same way as indicated by {@link GnssClock#getType()}.
+ *
+ * The reference receiver's time from which this is offset is specified by
+ * {@link GnssClock#getTimeInNs()}.
*
* The sign of this value is given by the following equation:
* measurement time = time_ns + time_offset_ns
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 22f4f04..a0dfaa0f 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -335,6 +335,24 @@
CHANNEL_OUT_LOW_FREQUENCY);
// CHANNEL_OUT_ALL is not yet defined; if added then it should match AUDIO_CHANNEL_OUT_ALL
+ /** Minimum value for sample rate,
+ * assuming AudioTrack and AudioRecord share the same limitations.
+ * @hide
+ */
+ // never unhide
+ public static final int SAMPLE_RATE_HZ_MIN = 4000;
+ /** Maximum value for sample rate,
+ * assuming AudioTrack and AudioRecord share the same limitations.
+ * @hide
+ */
+ // never unhide
+ public static final int SAMPLE_RATE_HZ_MAX = 192000;
+ /** Sample rate will be a route-dependent value.
+ * For AudioTrack, it is usually the sink sample rate,
+ * and for AudioRecord it is usually the source sample rate.
+ */
+ public static final int SAMPLE_RATE_UNSPECIFIED = 0;
+
/**
* @hide
* Return the input channel mask corresponding to an output channel mask.
@@ -561,7 +579,7 @@
}
/**
- * Constructor used by the JNI
+ * Constructor used by the JNI. Parameters are not checked for validity.
*/
// Update sound trigger JNI in core/jni/android_hardware_SoundTrigger.cpp when modifying this
// constructor
@@ -610,12 +628,9 @@
/**
* Return the sample rate.
* @return one of the values that can be set in {@link Builder#setSampleRate(int)} or
- * 0 if not set.
+ * {@link #SAMPLE_RATE_UNSPECIFIED} if not set.
*/
public int getSampleRate() {
- if ((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) == 0) {
- return 0;
- }
return mSampleRate;
}
@@ -687,7 +702,7 @@
*/
public static class Builder {
private int mEncoding = ENCODING_INVALID;
- private int mSampleRate = 0;
+ private int mSampleRate = SAMPLE_RATE_UNSPECIFIED;
private int mChannelMask = CHANNEL_INVALID;
private int mChannelIndexMask = 0;
private int mPropertySetMask = AUDIO_FORMAT_HAS_PROPERTY_NONE;
@@ -718,6 +733,8 @@
public AudioFormat build() {
AudioFormat af = new AudioFormat(1980/*ignored*/);
af.mEncoding = mEncoding;
+ // not calling setSampleRate is equivalent to calling
+ // setSampleRate(SAMPLE_RATE_UNSPECIFIED)
af.mSampleRate = mSampleRate;
af.mChannelMask = mChannelMask;
af.mChannelIndexMask = mChannelIndexMask;
@@ -795,7 +812,7 @@
* are specified but do not have the same channel count.
*/
public @NonNull Builder setChannelMask(int channelMask) {
- if (channelMask == 0) {
+ if (channelMask == CHANNEL_INVALID) {
throw new IllegalArgumentException("Invalid zero channel mask");
} else if (/* channelMask != 0 && */ mChannelIndexMask != 0 &&
Integer.bitCount(channelMask) != Integer.bitCount(mChannelIndexMask)) {
@@ -867,7 +884,11 @@
* @throws java.lang.IllegalArgumentException
*/
public Builder setSampleRate(int sampleRate) throws IllegalArgumentException {
- if ((sampleRate <= 0) || (sampleRate > 192000)) {
+ // TODO Consider whether to keep the MIN and MAX range checks here.
+ // It is not necessary and poses the problem of defining the limits independently from
+ // native implementation or platform capabilities.
+ if (((sampleRate < SAMPLE_RATE_HZ_MIN) || (sampleRate > SAMPLE_RATE_HZ_MAX)) &&
+ sampleRate != SAMPLE_RATE_UNSPECIFIED) {
throw new IllegalArgumentException("Invalid sample rate " + sampleRate);
}
mSampleRate = sampleRate;
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index dc534be..38e3b15 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3321,6 +3321,7 @@
* Used as a key for {@link #getProperty} to request the native or optimal output sample rate
* for this device's primary output stream, in decimal Hz.
*/
+ // FIXME Deprecate
public static final String PROPERTY_OUTPUT_SAMPLE_RATE =
"android.media.property.OUTPUT_SAMPLE_RATE";
@@ -3328,6 +3329,7 @@
* Used as a key for {@link #getProperty} to request the native or optimal output buffer size
* for this device's primary output stream, in decimal PCM frames.
*/
+ // FIXME Deprecate
public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER =
"android.media.property.OUTPUT_FRAMES_PER_BUFFER";
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index e342385..8f6b178 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -57,10 +57,6 @@
// Constants
//--------------------
- /** Minimum value for sample rate */
- private static final int SAMPLE_RATE_HZ_MIN = 4000;
- /** Maximum value for sample rate */
- private static final int SAMPLE_RATE_HZ_MAX = 192000;
/**
* indicates AudioRecord state is not successfully initialized.
@@ -168,8 +164,9 @@
//--------------------
/**
* The audio data sampling rate in Hz.
+ * Never {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED}.
*/
- private int mSampleRate;
+ private int mSampleRate; // initialized by all constructors via audioParamCheck()
/**
* The number of input audio channels (1 is mono, 2 is stereo)
*/
@@ -251,6 +248,9 @@
* @param sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only
* rate that is guaranteed to work on all devices, but other rates such as 22050,
* 16000, and 11025 may work on some devices.
+ * {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value
+ * which is usually the sample rate of the source.
+ * {@link #getSampleRate()} can be used to retrieve the actual sample rate chosen.
* @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_IN_MONO} and
* {@link AudioFormat#CHANNEL_IN_STEREO}. {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed
@@ -337,16 +337,9 @@
mAudioAttributes = attributes;
}
- int rate = 0;
- if ((format.getPropertySetMask()
- & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0)
- {
- rate = format.getSampleRate();
- } else {
- rate = AudioSystem.getPrimaryOutputSamplingRate();
- if (rate <= 0) {
- rate = 44100;
- }
+ int rate = format.getSampleRate();
+ if (rate == AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
+ rate = 0;
}
int encoding = AudioFormat.ENCODING_DEFAULT;
@@ -373,12 +366,13 @@
audioBuffSizeCheck(bufferSizeInBytes);
+ int[] sampleRate = new int[] {mSampleRate};
int[] session = new int[1];
session[0] = sessionId;
//TODO: update native initialization when information about hardware init failure
// due to capture device already open is available.
int initResult = native_setup( new WeakReference<AudioRecord>(this),
- mAudioAttributes, mSampleRate, mChannelMask, mChannelIndexMask,
+ mAudioAttributes, sampleRate, mChannelMask, mChannelIndexMask,
mAudioFormat, mNativeBufferSizeInBytes,
session, ActivityThread.currentOpPackageName());
if (initResult != SUCCESS) {
@@ -386,6 +380,7 @@
return; // with mState == STATE_UNINITIALIZED
}
+ mSampleRate = sampleRate[0];
mSessionId = session[0];
mState = STATE_INITIALIZED;
@@ -623,6 +618,7 @@
return mask;
}
+
// postconditions:
// mRecordSource is valid
// mAudioFormat is valid
@@ -642,7 +638,9 @@
//--------------
// sample rate
- if ((sampleRateInHz < SAMPLE_RATE_HZ_MIN) || (sampleRateInHz > SAMPLE_RATE_HZ_MAX)) {
+ if ((sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN ||
+ sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) &&
+ sampleRateInHz != AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
throw new IllegalArgumentException(sampleRateInHz
+ "Hz is not a supported sample rate.");
}
@@ -714,7 +712,11 @@
// Getters
//--------------------
/**
- * Returns the configured audio data sample rate in Hz
+ * Returns the configured audio sink sample rate in Hz.
+ * The sink sample rate never changes after construction.
+ * If the constructor had a specific sample rate, then the sink sample rate is that value.
+ * If the constructor had {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED},
+ * then the sink sample rate is a route-dependent default value based on the source [sic].
*/
public int getSampleRate() {
return mSampleRate;
@@ -861,6 +863,7 @@
* See {@link #AudioRecord(int, int, int, int, int)} for more information on valid
* configuration values.
* @param sampleRateInHz the sample rate expressed in Hertz.
+ * {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} is not permitted.
* @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_IN_MONO} and
* {@link AudioFormat#CHANNEL_IN_STEREO}
@@ -1708,7 +1711,7 @@
private native final int native_setup(Object audiorecord_this,
Object /*AudioAttributes*/ attributes,
- int sampleRate, int channelMask, int channelIndexMask, int audioFormat,
+ int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
int buffSizeInBytes, int[] sessionId, String opPackageName);
// TODO remove: implementation calls directly into implementation of native_release()
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 6fc2f87..708768c 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -91,11 +91,6 @@
*/
private static final float GAIN_MAX = 1.0f;
- /** Minimum value for sample rate */
- private static final int SAMPLE_RATE_HZ_MIN = 4000;
- /** Maximum value for sample rate */
- private static final int SAMPLE_RATE_HZ_MAX = 192000;
-
/** Maximum value for AudioTrack channel count
* @hide public for MediaCode only, do not un-hide or change to a numeric literal
*/
@@ -254,6 +249,7 @@
private final Looper mInitializationLooper;
/**
* The audio data source sampling rate in Hz.
+ * Never {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED}.
*/
private int mSampleRate; // initialized by all constructors via audioParamCheck()
/**
@@ -340,6 +336,9 @@
* {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC},
* {@link AudioManager#STREAM_ALARM}, and {@link AudioManager#STREAM_NOTIFICATION}.
* @param sampleRateInHz the initial source sample rate expressed in Hz.
+ * {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value
+ * which is usually the sample rate of the sink.
+ * {@link #getSampleRate()} can be used to retrieve the actual sample rate chosen.
* @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_OUT_MONO} and
* {@link AudioFormat#CHANNEL_OUT_STEREO}
@@ -389,6 +388,8 @@
* {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC},
* {@link AudioManager#STREAM_ALARM}, and {@link AudioManager#STREAM_NOTIFICATION}.
* @param sampleRateInHz the initial source sample rate expressed in Hz.
+ * {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value
+ * which is usually the sample rate of the sink.
* @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_OUT_MONO} and
* {@link AudioFormat#CHANNEL_OUT_STEREO}
@@ -461,16 +462,11 @@
looper = Looper.getMainLooper();
}
- int rate = 0;
- if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0)
- {
- rate = format.getSampleRate();
- } else {
- rate = AudioSystem.getPrimaryOutputSamplingRate();
- if (rate <= 0) {
- rate = 44100;
- }
+ int rate = format.getSampleRate();
+ if (rate == AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
+ rate = 0;
}
+
int channelIndexMask = 0;
if ((format.getPropertySetMask()
& AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0) {
@@ -503,17 +499,19 @@
throw new IllegalArgumentException("Invalid audio session ID: "+sessionId);
}
+ int[] sampleRate = new int[] {mSampleRate};
int[] session = new int[1];
session[0] = sessionId;
// native initialization
int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
- mSampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
+ sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
mNativeBufferSizeInBytes, mDataLoadMode, session);
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing AudioTrack.");
return; // with mState == STATE_UNINITIALIZED
}
+ mSampleRate = sampleRate[0];
mSessionId = session[0];
if (mDataLoadMode == MODE_STATIC) {
@@ -712,7 +710,7 @@
if (mFormat == null) {
mFormat = new AudioFormat.Builder()
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
- .setSampleRate(AudioSystem.getPrimaryOutputSamplingRate())
+ //.setSampleRate(AudioFormat.SAMPLE_RATE_UNSPECIFIED)
.setEncoding(AudioFormat.ENCODING_DEFAULT)
.build();
}
@@ -762,7 +760,9 @@
int audioFormat, int mode) {
//--------------
// sample rate, note these values are subject to change
- if (sampleRateInHz < SAMPLE_RATE_HZ_MIN || sampleRateInHz > SAMPLE_RATE_HZ_MAX) {
+ if ((sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN ||
+ sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) &&
+ sampleRateInHz != AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
throw new IllegalArgumentException(sampleRateInHz
+ "Hz is not a supported sample rate.");
}
@@ -948,7 +948,13 @@
}
/**
- * Returns the configured audio data sample rate in Hz
+ * Returns the configured audio source sample rate in Hz.
+ * The initial source sample rate depends on the constructor parameters,
+ * but the source sample rate may change if {@link #setPlaybackRate(int)} is called.
+ * If the constructor had a specific sample rate, then the initial sink sample rate is that
+ * value.
+ * If the constructor had {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED},
+ * then the initial sink sample rate is a route-dependent default value based on the source [sic].
*/
public int getSampleRate() {
return mSampleRate;
@@ -1218,6 +1224,7 @@
* to a higher value than the initial source sample rate, be sure to configure the buffer size
* based on the highest planned sample rate.
* @param sampleRateInHz the source sample rate expressed in Hz.
+ * {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} is not permitted.
* @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_OUT_MONO} and
* {@link AudioFormat#CHANNEL_OUT_STEREO}
@@ -1255,7 +1262,9 @@
}
// sample rate, note these values are subject to change
- if ( (sampleRateInHz < SAMPLE_RATE_HZ_MIN) || (sampleRateInHz > SAMPLE_RATE_HZ_MAX) ) {
+ // Note: AudioFormat.SAMPLE_RATE_UNSPECIFIED is not allowed
+ if ( (sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN) ||
+ (sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) ) {
loge("getMinBufferSize(): " + sampleRateInHz + " Hz is not a supported sample rate.");
return ERROR_BAD_VALUE;
}
@@ -2763,7 +2772,7 @@
// AudioAttributes.USAGE_MEDIA will map to AudioManager.STREAM_MUSIC
private native final int native_setup(Object /*WeakReference<AudioTrack>*/ audiotrack_this,
Object /*AudioAttributes*/ attributes,
- int sampleRate, int channelMask, int channelIndexMask, int audioFormat,
+ int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
int buffSizeInBytes, int mode, int[] sessionId);
private native final void native_finalize();
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index 4ffac6d..55fb82b 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -277,6 +277,7 @@
mRouteFlags = ROUTE_FLAG_RENDER;
}
if (mFormat == null) {
+ // FIXME Can we eliminate this? Will AudioMix work with an unspecified sample rate?
int rate = AudioSystem.getPrimaryOutputSamplingRate();
if (rate <= 0) {
rate = 44100;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index 2ae3ec62..7a6aad6 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -16,6 +16,7 @@
package com.android.printspooler.model;
+import android.annotation.NonNull;
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
@@ -57,6 +58,8 @@
private static final boolean DEBUG = false;
+ private static final long FORCE_CANCEL_TIMEOUT = 1000; // ms
+
private static final int STATE_INITIAL = 0;
private static final int STATE_STARTED = 1;
private static final int STATE_UPDATING = 2;
@@ -212,7 +215,7 @@
// cancellation and start over.
if (mCurrentCommand != null && (mCurrentCommand.isRunning()
|| mCurrentCommand.isPending())) {
- mCurrentCommand.cancel();
+ mCurrentCommand.cancel(false);
}
// Schedule a layout command.
@@ -233,7 +236,7 @@
// Cancel the current write as a new one is to be scheduled.
if (mCurrentCommand instanceof WriteCommand
&& (mCurrentCommand.isPending() || mCurrentCommand.isRunning())) {
- mCurrentCommand.cancel();
+ mCurrentCommand.cancel(false);
}
// Schedule a write command.
@@ -277,9 +280,9 @@
}
}
- public void cancel() {
+ public void cancel(boolean force) {
if (DEBUG) {
- Log.i(LOG_TAG, "[CALLED] cancel()");
+ Log.i(LOG_TAG, "[CALLED] cancel(" + force + ")");
}
mNextCommand = null;
@@ -290,7 +293,7 @@
mState = STATE_CANCELING;
- mCurrentCommand.cancel();
+ mCurrentCommand.cancel(force);
}
public void destroy() {
@@ -441,8 +444,9 @@
if (mCurrentCommand != null) {
if (mCurrentCommand.isPending()) {
mCurrentCommand.run();
+
+ mState = STATE_UPDATING;
}
- mState = STATE_UPDATING;
} else {
mState = STATE_UPDATED;
}
@@ -535,14 +539,17 @@
protected final CommandDoneCallback mDoneCallback;
+ private final Handler mHandler;
+
protected ICancellationSignal mCancellation;
private CharSequence mError;
private int mState = STATE_PENDING;
- public AsyncCommand(IPrintDocumentAdapter adapter, RemotePrintDocumentInfo document,
+ public AsyncCommand(Looper looper, IPrintDocumentAdapter adapter, RemotePrintDocumentInfo document,
CommandDoneCallback doneCallback) {
+ mHandler = new AsyncCommandHandler(looper);
mAdapter = adapter;
mDocument = document;
mDoneCallback = doneCallback;
@@ -556,7 +563,29 @@
return mState == STATE_CANCELED;
}
- public final void cancel() {
+ /**
+ * If a force cancel is pending, remove it. This is usually called when a command returns
+ * and thereby does not need to be canceled anymore.
+ */
+ protected void removeForceCancel() {
+ if (DEBUG) {
+ if (mHandler.hasMessages(AsyncCommandHandler.MSG_FORCE_CANCEL)) {
+ Log.i(LOG_TAG, "[FORCE CANCEL] Removed");
+ }
+ }
+
+ mHandler.removeMessages(AsyncCommandHandler.MSG_FORCE_CANCEL);
+ }
+
+ /**
+ * Cancel the current command.
+ *
+ * @param force If set, does not wait for the {@link PrintDocumentAdapter} to cancel. This
+ * should only be used if this is the last command send to the as otherwise the
+ * {@link PrintDocumentAdapter adapter} might get commands while it is still
+ * running the old one.
+ */
+ public final void cancel(boolean force) {
if (isRunning()) {
canceling();
if (mCancellation != null) {
@@ -566,14 +595,25 @@
Log.w(LOG_TAG, "Error while canceling", re);
}
}
- } else if (isCanceling()) {
- // Nothing to do
- } else {
- canceled();
-
- // Done.
- mDoneCallback.onDone();
}
+
+ if (isCanceling()) {
+ if (force) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[FORCE CANCEL] queued");
+ }
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(AsyncCommandHandler.MSG_FORCE_CANCEL),
+ FORCE_CANCEL_TIMEOUT);
+ }
+
+ return;
+ }
+
+ canceled();
+
+ // Done.
+ mDoneCallback.onDone();
}
protected final void canceling() {
@@ -617,7 +657,7 @@
}
protected final void failed(CharSequence error) {
- if (mState != STATE_RUNNING) {
+ if (mState != STATE_RUNNING && mState != STATE_CANCELING) {
throw new IllegalStateException("Not running.");
}
mState = STATE_FAILED;
@@ -632,6 +672,37 @@
public CharSequence getError() {
return mError;
}
+
+ /**
+ * Handler for the async command.
+ */
+ private class AsyncCommandHandler extends Handler {
+ /** Message indicated the desire for to force cancel a command */
+ final static int MSG_FORCE_CANCEL = 0;
+
+ AsyncCommandHandler(@NonNull Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_FORCE_CANCEL:
+ if (isCanceling()) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[FORCE CANCEL] executed");
+ }
+ failed("Command did not respond to cancellation in "
+ + FORCE_CANCEL_TIMEOUT + " ms");
+
+ mDoneCallback.onDone();
+ }
+ break;
+ default:
+ // not reached;
+ }
+ }
+ }
}
private static final class LayoutCommand extends AsyncCommand {
@@ -646,7 +717,7 @@
public LayoutCommand(Looper looper, IPrintDocumentAdapter adapter,
RemotePrintDocumentInfo document, PrintAttributes oldAttributes,
PrintAttributes newAttributes, boolean preview, CommandDoneCallback callback) {
- super(adapter, document, callback);
+ super(looper, adapter, document, callback);
mHandler = new LayoutHandler(looper);
mRemoteResultCallback = new LayoutResultCallback(mHandler);
mOldAttributes.copyFrom(oldAttributes);
@@ -795,6 +866,21 @@
@Override
public void handleMessage(Message message) {
+ // The command might have been force canceled, see
+ // AsyncCommand.AsyncCommandHandler#handleMessage
+ if (isFailed()) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLBACK] on canceled layout command");
+ }
+
+ return;
+ } else {
+ if (message.what != MSG_ON_LAYOUT_STARTED) {
+ // No need to force cancel anymore if layout finished
+ removeForceCancel();
+ }
+ }
+
switch (message.what) {
case MSG_ON_LAYOUT_STARTED: {
ICancellationSignal cancellation = (ICancellationSignal) message.obj;
@@ -882,7 +968,7 @@
public WriteCommand(Context context, Looper looper, IPrintDocumentAdapter adapter,
RemotePrintDocumentInfo document, int pageCount, PageRange[] pages,
MutexFileProvider fileProvider, CommandDoneCallback callback) {
- super(adapter, document, callback);
+ super(looper, adapter, document, callback);
mContext = context;
mHandler = new WriteHandler(looper);
mRemoteResultCallback = new WriteResultCallback(mHandler);
@@ -1052,6 +1138,21 @@
@Override
public void handleMessage(Message message) {
+ // The command might have been force canceled, see
+ // AsyncCommand.AsyncCommandHandler#handleMessage
+ if (isFailed()) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLBACK] on canceled write command");
+ }
+
+ return;
+ } else {
+ if (message.what != MSG_ON_WRITE_STARTED) {
+ // No need to force cancel anymore if write finished
+ removeForceCancel();
+ }
+ }
+
switch (message.what) {
case MSG_ON_WRITE_STARTED: {
ICancellationSignal cancellation = (ICancellationSignal) message.obj;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 08cd0b6..64f5cc6 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -320,8 +320,8 @@
if (isFinishing() || (isFinalState(mState) && !mPrintedDocument.isUpdating())) {
return;
}
- mPrintedDocument.cancel();
setState(STATE_PRINT_CANCELED);
+ mPrintedDocument.cancel(true);
doFinish();
}
}, PrintActivity.this);
@@ -1013,7 +1013,7 @@
}
private void requestCreatePdfFileOrFinish() {
- mPrintedDocument.cancel();
+ mPrintedDocument.cancel(false);
if (mCurrentPrinter == mDestinationSpinnerAdapter.getPdfPrinter()) {
startCreateDocumentActivity();
@@ -1130,7 +1130,7 @@
private void cancelPrint() {
setState(STATE_PRINT_CANCELED);
updateOptionsUi();
- mPrintedDocument.cancel();
+ mPrintedDocument.cancel(true);
doFinish();
}
@@ -1889,7 +1889,7 @@
public void onPrinterUnavailable(PrinterInfo printer) {
if (mCurrentPrinter.getId().equals(printer.getId())) {
setState(STATE_PRINTER_UNAVAILABLE);
- mPrintedDocument.cancel();
+ mPrintedDocument.cancel(false);
ensureErrorUiShown(getString(R.string.print_error_printer_unavailable),
PrintErrorFragment.ACTION_NONE);
updateOptionsUi();
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index 1c032fa..a578055 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -18,6 +18,7 @@
import android.annotation.LayoutRes;
import android.annotation.Nullable;
import android.app.Activity;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -235,20 +236,24 @@
Intent.FLAG_ACTIVITY_CLEAR_TASK));
return true;
}
- int numUserHandles = tile.userHandle.size();
- if (numUserHandles > 1) {
- ProfileSelectDialog.show(getFragmentManager(), tile);
- return false;
- } else if (numUserHandles == 1) {
- // Show menu on top level items.
- tile.intent.putExtra(EXTRA_SHOW_MENU, true);
- tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- startActivityAsUser(tile.intent, tile.userHandle.get(0));
- } else {
- // Show menu on top level items.
- tile.intent.putExtra(EXTRA_SHOW_MENU, true);
- tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- startActivity(tile.intent);
+ try {
+ int numUserHandles = tile.userHandle.size();
+ if (numUserHandles > 1) {
+ ProfileSelectDialog.show(getFragmentManager(), tile);
+ return false;
+ } else if (numUserHandles == 1) {
+ // Show menu on top level items.
+ tile.intent.putExtra(EXTRA_SHOW_MENU, true);
+ tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ startActivityAsUser(tile.intent, tile.userHandle.get(0));
+ } else {
+ // Show menu on top level items.
+ tile.intent.putExtra(EXTRA_SHOW_MENU, true);
+ tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ startActivity(tile.intent);
+ }
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, "Couldn't find tile " + tile.intent, e);
}
return true;
}
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index c99ec91..587fd6c 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -706,7 +706,7 @@
}
final File screenshotFile = new File((String) resultMsg.obj);
- final int msgId;
+ final String msg;
if (taken) {
info.addScreenshot(screenshotFile);
if (info.finished) {
@@ -714,14 +714,13 @@
info.renameScreenshots(mScreenshotsDir);
sendBugreportNotification(mContext, info);
}
- msgId = R.string.bugreport_screenshot_taken;
+ msg = mContext.getString(R.string.bugreport_screenshot_taken);
} else {
// TODO: try again using Framework APIs instead of relying on screencap.
- msgId = R.string.bugreport_screenshot_failed;
+ msg = mContext.getString(R.string.bugreport_screenshot_failed);
+ Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
}
- final String msg = mContext.getString(msgId);
Log.d(TAG, msg);
- Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
}
/**
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 88313bb..ad3c26b 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -1,10 +1,24 @@
LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := SystemUI-proto-tags
+
+LOCAL_SRC_FILES := $(call all-proto-files-under,src) \
+ src/com/android/systemui/EventLogTags.logtags
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# ------------------
+
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-proto-files-under,src) $(call all-Iaidl-files-under, src) \
- src/com/android/systemui/EventLogTags.logtags
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := \
Keyguard \
@@ -13,13 +27,12 @@
android-support-v7-appcompat \
android-support-v14-preference \
android-support-v17-leanback \
- framework-protos
+ framework-protos \
+ SystemUI-proto-tags
LOCAL_JAVA_LIBRARIES := telephony-common
LOCAL_PACKAGE_NAME := SystemUI
-LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
new file mode 100644
index 0000000..5cabb77a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <size
+ android:width="36dp"
+ android:height="36dp" />
+ <solid
+ android:color="#4DFFFFFF" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/tv_pip_close_button.xml b/packages/SystemUI/res/drawable/tv_pip_close_button.xml
new file mode 100644
index 0000000..86fda0d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_close_button.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:constantSize="true">
+ <item android:state_focused="true">
+ <layer-list>
+ <item android:drawable="@drawable/tv_pip_button_focused" />
+ <item android:drawable="@drawable/ic_close_white" />
+ </layer-list>
+ </item>
+ <item android:drawable="@drawable/ic_close_white" />
+</selector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_full_button.xml b/packages/SystemUI/res/drawable/tv_pip_full_button.xml
new file mode 100644
index 0000000..332c669
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_full_button.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:constantSize="true">
+ <item android:state_focused="true">
+ <layer-list>
+ <item android:drawable="@drawable/tv_pip_button_focused" />
+ <item android:drawable="@drawable/ic_fullscreen_white_24dp" />
+ </layer-list>
+ </item>
+ <item android:drawable="@drawable/ic_fullscreen_white_24dp" />
+</selector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_outline.xml b/packages/SystemUI/res/drawable/tv_pip_outline.xml
new file mode 100644
index 0000000..c84438c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_outline.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke android:width="2dp" android:color="#EEEEEE" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/tv_pip_pause_button.xml b/packages/SystemUI/res/drawable/tv_pip_pause_button.xml
new file mode 100644
index 0000000..d277b07
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_pause_button.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:constantSize="true">
+ <item android:state_focused="true">
+ <layer-list>
+ <item android:drawable="@drawable/tv_pip_button_focused" />
+ <item android:drawable="@drawable/ic_pause_white_24dp" />
+ </layer-list>
+ </item>
+ <item android:drawable="@drawable/ic_pause_white_24dp" />
+</selector>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 3ee2475..994d3c9 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -28,9 +28,7 @@
android:layout_marginTop="@dimen/status_bar_header_height"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingBottom="8dp"
- android:clipToPadding="false"
- android:clipChildren="false" />
+ android:paddingBottom="8dp" />
<include layout="@layout/quick_status_bar_expanded_header" />
diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml
index 2e41561..fa65758 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header.xml
@@ -30,21 +30,41 @@
android:paddingBottom="8dp"
android:paddingStart="12dp"
android:paddingEnd="16dp" />
- <TextView
- android:id="@+id/title"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:layout_marginStart="56dp"
- android:layout_marginEnd="112dp"
- android:textSize="16sp"
- android:textColor="#ffffffff"
- android:text="@string/recents_empty_message"
- android:fontFamily="sans-serif-medium"
- android:singleLine="true"
- android:maxLines="2"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal" />
+ android:layout_marginEnd="56dp"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textSize="16sp"
+ android:textColor="#ffffffff"
+ android:text="@string/recents_empty_message"
+ android:fontFamily="sans-serif-medium"
+ android:singleLine="true"
+ android:maxLines="1"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+ <TextView
+ android:id="@+id/sub_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textSize="11sp"
+ android:textColor="#ffffffff"
+ android:text="@string/recents_launch_non_dockable_task_label"
+ android:fontFamily="sans-serif-medium"
+ android:singleLine="true"
+ android:maxLines="1"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:visibility="gone" />
+ </LinearLayout>
<com.android.systemui.recents.views.FixedSizeImageView
android:id="@+id/move_task"
android:layout_width="@dimen/recents_task_view_header_button_width"
diff --git a/packages/SystemUI/res/layout/tv_pip_menu.xml b/packages/SystemUI/res/layout/tv_pip_menu.xml
index 3562c644..0b98d0e 100644
--- a/packages/SystemUI/res/layout/tv_pip_menu.xml
+++ b/packages/SystemUI/res/layout/tv_pip_menu.xml
@@ -18,36 +18,94 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_gravity="end"
- android:paddingStart="10dp"
- android:paddingEnd="10dp"
- android:background="#88FFFFFF"
- android:gravity="center_vertical" >
+ android:orientation="horizontal"
+ android:paddingTop="350dp"
+ android:background="#CC000000"
+ android:gravity="top|center_horizontal"
+ android:clipChildren="false">
- <Button android:id="@+id/full"
- android:layout_width="match_parent"
+ <LinearLayout
+ android:layout_width="34dp"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:text="@string/pip_fullscreen"
- android:textSize="10sp"
- android:focusable="true" />
+ android:layout_marginEnd="3dp"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:clipChildren="false">
- <Button android:id="@+id/exit"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:text="@string/pip_exit"
- android:textSize="10sp"
- android:focusable="true" />
+ <ImageView android:id="@+id/full"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:src="@drawable/tv_pip_full_button" />
- <Button android:id="@+id/cancel"
- android:layout_width="match_parent"
+ <TextView android:id="@+id/full_desc"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="3dp"
+ android:gravity="center"
+ android:visibility="invisible"
+ android:text="@string/pip_fullscreen"
+ android:fontFamily="sans-serif"
+ android:textSize="12sp"
+ android:textColor="#EEEEEE"
+ android:clipChildren="false" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="34dp"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:text="@string/pip_cancel"
- android:textSize="10sp"
- android:focusable="true" />
+ android:layout_marginStart="3dp"
+ android:layout_marginEnd="3dp"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:visibility="gone"
+ android:clipChildren="false">
+
+ <ImageView android:id="@+id/play_pause"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:src="@drawable/tv_pip_pause_button" />
+
+ <TextView android:id="@+id/play_pause_desc"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="3dp"
+ android:gravity="center"
+ android:visibility="invisible"
+ android:text="@string/pip_pause"
+ android:fontFamily="sans-serif"
+ android:textSize="12sp"
+ android:textColor="#EEEEEE"
+ android:clipChildren="false" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="34dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="3dp"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:clipChildren="false">
+
+ <ImageView android:id="@+id/close"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:src="@drawable/tv_pip_close_button" />
+
+ <TextView android:id="@+id/close_desc"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="3dp"
+ android:gravity="center"
+ android:visibility="invisible"
+ android:text="@string/pip_close"
+ android:fontFamily="sans-serif"
+ android:textSize="12sp"
+ android:textColor="#EEEEEE"
+ android:clipChildren="false" />
+ </LinearLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_onboarding.xml b/packages/SystemUI/res/layout/tv_pip_onboarding.xml
index ef39555..f031bb4 100644
--- a/packages/SystemUI/res/layout/tv_pip_onboarding.xml
+++ b/packages/SystemUI/res/layout/tv_pip_onboarding.xml
@@ -18,34 +18,43 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/pip_onboarding"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#C00288D1"
- android:gravity="center"
- android:orientation="vertical" >
+ android:gravity="top|center_horizontal"
+ android:orientation="vertical">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="30sp"
- android:textColor="@android:color/white"
- android:text="@string/pip_onboarding_title" />
+ <!-- A rectangle arounds the PIP.
+ Size and positions will be programatically set up
+ to comply with config_defaultPictureInPictureBounds. -->
<ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_sysbar_home" />
+ android:id="@+id/pip_outline"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:src="@drawable/tv_pip_outline" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="30dp"
- android:textSize="13sp"
- android:textColor="@android:color/white"
+ android:layout_marginTop="24dp"
+ android:fontFamily="sans-serif"
+ android:textSize="16sp"
+ android:textColor="#EEEEEE"
+ android:lineSpacingMultiplier="1.28"
android:text="@string/pip_onboarding_description" />
<Button
android:id="@+id/close"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="15sp"
+ android:layout_height="36dp"
+ android:layout_marginTop="24dp"
+ android:gravity="center"
+ android:paddingStart="24dp"
+ android:paddingEnd="24dp"
+ android:fontFamily="sans-serif-condensed"
+ android:textSize="16sp"
+ android:textColor="#026089"
android:textAllCaps="true"
- android:text="@string/pip_onboarding_button" />
+ android:text="@string/pip_onboarding_button"
+ android:background="#EEEEEE"
+ android:elevation="4dp" />
</LinearLayout>
diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml
index 4d7d6b5..791d761 100644
--- a/packages/SystemUI/res/values-sw600dp/styles.xml
+++ b/packages/SystemUI/res/values-sw600dp/styles.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer">
- <item name="android:layout_width">480dp</item>
+ <item name="android:layout_width">@dimen/standard_notification_panel_width</item>
</style>
<style name="UserDetailView">
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
index 77605bd..bf32cc7 100644
--- a/packages/SystemUI/res/values/dimens_tv.xml
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -31,4 +31,7 @@
<!-- Values for focus animation -->
<dimen name="recents_tv_unselected_item_z">6dp</dimen>
<dimen name="recents_tv_selected_item_z_delta">10dp</dimen>
-</resources>
\ No newline at end of file
+
+ <!-- Extra space around the PIP and its outline in PIP onboarding activity -->
+ <dimen name="tv_pip_bounds_space">3dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 30c0be8..ac6e3ac 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -722,6 +722,10 @@
<string name="recents_history_button_label">History</string>
<!-- Recents: History clear all string. [CHAR LIMIT=NONE] -->
<string name="recents_history_clear_all_button_label">Clear</string>
+ <!-- Recents: Non-dockable task drag message. [CHAR LIMIT=NONE] -->
+ <string name="recents_drag_non_dockable_task_message">This app does not support multi-window</string>
+ <!-- Recents: Non-dockable task launch sub header. [CHAR LIMIT=NONE] -->
+ <string name="recents_launch_non_dockable_task_label">App does not support multi-window</string>
<!-- Recents: MultiStack add stack split horizontal radio button. [CHAR LIMIT=NONE] -->
<string name="recents_multistack_add_stack_dialog_split_horizontal">Split Horizontal</string>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index 7c4768d..4f382ea 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -20,7 +20,7 @@
<!-- Picture-in-Picture menu -->
<eat-comment />
<!-- Button to close PIP on PIP UI -->
- <string name="pip_exit" translatable="false">Close PIP</string>
+ <string name="pip_close" translatable="false">Close PIP</string>
<!-- Button to move PIP screen to the fullscreen on PIP UI -->
<string name="pip_fullscreen" translatable="false">Full screen</string>
<!-- Button to play the current media on PIP UI -->
@@ -34,8 +34,6 @@
<!-- Picture-in-Picture onboarding screen -->
<eat-comment />
- <!-- Title for onboarding screen. -->
- <string name="pip_onboarding_title" translatable="false">Picture-in-picture</string>
<!-- Description for onboarding screen. -->
<string name="pip_onboarding_description" translatable="false">Press and hold the HOME\nbutton to close or control it</string>
<!-- Button to close onboarding screen. -->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 0915ee1..2c5cb89 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -38,7 +38,7 @@
if (mPageIndicator == null) return;
mPageIndicator.setLocation(position);
if (mPageListener != null) {
- mPageListener.onPageChanged(position);
+ mPageListener.onPageChanged(position == 0);
}
}
@@ -47,6 +47,9 @@
int positionOffsetPixels) {
if (mPageIndicator == null) return;
mPageIndicator.setLocation(position + positionOffset);
+ if (mPageListener != null) {
+ mPageListener.onPageChanged(position == 0 && positionOffsetPixels == 0);
+ }
}
@Override
@@ -57,6 +60,11 @@
}
@Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ @Override
protected void onFinishInflate() {
super.onFinishInflate();
mPageIndicator = (PageIndicator) findViewById(R.id.page_indicator);
@@ -209,6 +217,6 @@
};
public interface PageListener {
- void onPageChanged(int page);
+ void onPageChanged(boolean isFirst);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index dc64591..c31bb33 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -69,11 +69,13 @@
}
@Override
- public void onPageChanged(int page) {
- mOnFirstPage = page == 0;
- if (!mOnFirstPage) {
+ public void onPageChanged(boolean isFirst) {
+ if (mOnFirstPage == isFirst) return;
+ if (!isFirst) {
+ setPosition(1);
clearAnimationState();
}
+ mOnFirstPage = isFirst;
}
private void updateAnimators() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index abe4c77..4408dbf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -183,5 +183,10 @@
// No resources here.
return false;
}
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
index 94d8524..026dd0e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
@@ -58,7 +58,7 @@
}
if (mListener != null) {
if (mLastT == 0 || mLastT == 1) {
- if (t != 0) {
+ if (t != mLastT) {
mListener.onAnimationStarted();
}
} else if (t == 1) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index c2a6108..c41098f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -528,17 +528,16 @@
@Override
public void onMultiWindowChanged(boolean inMultiWindow) {
super.onMultiWindowChanged(inMultiWindow);
- if (!inMultiWindow) {
- RecentsTaskLoader loader = Recents.getTaskLoader();
- RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
- launchOpts.loadIcons = false;
- launchOpts.loadThumbnails = false;
- launchOpts.onlyLoadForCache = true;
- RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
- loader.preloadTasks(loadPlan, -1, false);
- loader.loadTasks(this, loadPlan, launchOpts);
- EventBus.getDefault().send(new TaskStackUpdatedEvent(loadPlan.getTaskStack()));
- }
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+ launchOpts.loadIcons = false;
+ launchOpts.loadThumbnails = false;
+ launchOpts.onlyLoadForCache = true;
+ RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
+ loader.preloadTasks(loadPlan, -1, false);
+ loader.loadTasks(this, loadPlan, launchOpts);
+ EventBus.getDefault().send(new TaskStackUpdatedEvent(loadPlan.getTaskStack(),
+ inMultiWindow));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 8de964b..28b2fae 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -161,10 +161,8 @@
Handler mHandler;
TaskStackListenerImpl mTaskStackListener;
RecentsAppWidgetHost mAppWidgetHost;
- boolean mBootCompleted;
boolean mCanReuseTaskStackViews = true;
boolean mDraggingInRecents;
- boolean mReloadTasks;
boolean mLaunchedWhileDocking;
// Task launching
@@ -236,7 +234,6 @@
}
public void onBootCompleted() {
- mBootCompleted = true;
updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */);
}
@@ -317,23 +314,21 @@
}
public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
- if (mBootCompleted) {
- if (triggeredFromAltTab && mFastAltTabTrigger.isDozing()) {
- // The user has released alt-tab before the trigger has run, so just show the next
- // task immediately
- showNextTask();
+ if (triggeredFromAltTab && mFastAltTabTrigger.isDozing()) {
+ // The user has released alt-tab before the trigger has run, so just show the next
+ // task immediately
+ showNextTask();
- // Cancel the fast alt-tab trigger
- mFastAltTabTrigger.stopDozing();
- mFastAltTabTrigger.resetTrigger();
- return;
- }
-
- // Defer to the activity to handle hiding recents, if it handles it, then it must still
- // be visible
- EventBus.getDefault().post(new HideRecentsEvent(triggeredFromAltTab,
- triggeredFromHomeKey));
+ // Cancel the fast alt-tab trigger
+ mFastAltTabTrigger.stopDozing();
+ mFastAltTabTrigger.resetTrigger();
+ return;
}
+
+ // Defer to the activity to handle hiding recents, if it handles it, then it must still
+ // be visible
+ EventBus.getDefault().post(new HideRecentsEvent(triggeredFromAltTab,
+ triggeredFromHomeKey));
}
public void toggleRecents() {
@@ -347,7 +342,6 @@
mTriggeredFromAltTab = false;
try {
- ViewConfiguration viewConfig = ViewConfiguration.get(mContext);
SystemServicesProxy ssp = Recents.getSystemServices();
ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
MutableBoolean isTopTaskHome = new MutableBoolean(true);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
index f87f6de..0d614e8c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
@@ -28,8 +28,10 @@
* A new TaskStack instance representing the latest stack state.
*/
public final TaskStack stack;
+ public final boolean inMultiWindow;
- public TaskStackUpdatedEvent(TaskStack stack) {
+ public TaskStackUpdatedEvent(TaskStack stack, boolean inMultiWindow) {
this.stack = stack;
+ this.inMultiWindow = inMultiWindow;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 824231a..6fef8a2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -198,8 +198,8 @@
// Add the task to the stack
Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
thumbnail, title, contentDescription, dismissDescription, activityColor,
- backgroundColor, !isStackTask, isLaunchTarget, isSystemApp, t.bounds,
- t.taskDescription);
+ backgroundColor, !isStackTask, isLaunchTarget, isSystemApp, t.isDockable,
+ t.bounds, t.taskDescription);
allTasks.add(task);
affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 8ed6dd7..e5d4f1b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -168,6 +168,8 @@
public boolean isHistorical;
@ViewDebug.ExportedProperty(category="recents")
public boolean isSystemApp;
+ @ViewDebug.ExportedProperty(category="recents")
+ public boolean isDockable;
private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
@@ -178,8 +180,8 @@
public Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon,
Bitmap thumbnail, String title, String contentDescription,
String dismissDescription, int colorPrimary, int colorBackground,
- boolean isHistorical, boolean isLaunchTarget, boolean isSystemApp, Rect bounds,
- ActivityManager.TaskDescription taskDescription) {
+ boolean isHistorical, boolean isLaunchTarget, boolean isSystemApp,
+ boolean isDockable, Rect bounds, ActivityManager.TaskDescription taskDescription) {
boolean isInAffiliationGroup = (affiliationTaskId != key.id);
boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0);
this.key = key;
@@ -199,6 +201,7 @@
this.isLaunchTarget = isLaunchTarget;
this.isHistorical = isHistorical;
this.isSystemApp = isSystemApp;
+ this.isDockable = isDockable;
}
/** Copies the other task. */
@@ -219,6 +222,7 @@
this.isLaunchTarget = o.isLaunchTarget;
this.isHistorical = o.isHistorical;
this.isSystemApp = o.isSystemApp;
+ this.isDockable = o.isDockable;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 2e45627..5dde926 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -663,8 +663,10 @@
}
public final void onBusEvent(TaskStackUpdatedEvent event) {
- mStack.setTasks(event.stack.computeAllTasksList(), true /* notifyStackChanges */);
- mStack.createAffiliatedGroupings(getContext());
+ if (!event.inMultiWindow) {
+ mStack.setTasks(event.stack.computeAllTasksList(), true /* notifyStackChanges */);
+ mStack.createAffiliatedGroupings(getContext());
+ }
}
public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 016d937..079d7b9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -21,7 +21,9 @@
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.ViewDebug;
+import android.widget.Toast;
+import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.events.EventBus;
@@ -148,11 +150,16 @@
mVisibleDockStates.clear();
if (!ssp.hasDockedTask() && mRv.getTaskStack().getTaskCount() > 1) {
- // Add the dock state drop targets (these take priority)
- TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation();
- for (TaskStack.DockState dockState : dockStates) {
- registerDropTargetForCurrentDrag(dockState);
- mVisibleDockStates.add(dockState);
+ if (!event.task.isDockable) {
+ Toast.makeText(mRv.getContext(), R.string.recents_drag_non_dockable_task_message,
+ Toast.LENGTH_SHORT).show();
+ } else {
+ // Add the dock state drop targets (these take priority)
+ TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation();
+ for (TaskStack.DockState dockState : dockStates) {
+ registerDropTargetForCurrentDrag(dockState);
+ mVisibleDockStates.add(dockState);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index d71d70f..e1a81c8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -1573,6 +1573,9 @@
Task launchTask = mStack.getStackTasks().get(launchTaskIndex);
EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(launchTask),
launchTask, null, INVALID_STACK_ID, false /* screenPinningRequested */));
+
+ MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_LAUNCH_PREVIOUS_TASK,
+ launchTask.key.getComponent().toString());
}
}
@@ -1830,12 +1833,28 @@
}
public final void onBusEvent(TaskStackUpdatedEvent event) {
- // Scroll the stack to the front after it has been updated
+ if (!event.inMultiWindow) {
+ // Scroll the stack to the front after it has been updated
+ event.addPostAnimationCallback(new Runnable() {
+ @Override
+ public void run() {
+ mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP,
+ null /* postScrollRunnable */);
+ }
+ });
+ }
+ // When the multi-window state changes, rebind all task view headers again to update their
+ // dockable state
event.addPostAnimationCallback(new Runnable() {
@Override
public void run() {
- mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP,
- null /* postScrollRunnable */);
+ List<TaskView> taskViews = getTaskViews();
+ int taskViewCount = taskViews.size();
+ for (int i = 0; i < taskViewCount; i++) {
+ TaskView tv = taskViews.get(i);
+ tv.getHeaderView().rebindToTask(tv.getTask(), tv.mTouchExplorationEnabled,
+ tv.mIsDisabledInSafeMode);
+ }
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 0543dd5..05a8527 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -139,6 +139,7 @@
// Header views
ImageView mIconView;
TextView mTitleView;
+ TextView mSubTitleView;
ImageView mMoveTaskButton;
ImageView mDismissButton;
ViewStub mAppOverlayViewStub;
@@ -237,6 +238,7 @@
mIconView.setClickable(false);
mIconView.setOnLongClickListener(this);
mTitleView = (TextView) findViewById(R.id.title);
+ mSubTitleView = (TextView) findViewById(R.id.sub_title);
mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
if (ssp.hasFreeformWorkspaceSupport()) {
mMoveTaskButton = (ImageView) findViewById(R.id.move_task);
@@ -367,6 +369,7 @@
/** Binds the bar view to the task */
public void rebindToTask(Task t, boolean touchExplorationEnabled, boolean disabledInSafeMode) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
mTask = t;
// If an activity icon is defined, then we use that as the primary icon to show in the bar,
@@ -384,6 +387,13 @@
mTitleView.setContentDescription(t.contentDescription);
mTitleView.setTextColor(t.useLightOnPrimaryColor ?
mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor);
+ if (!t.isDockable && ssp.hasDockedTask()) {
+ mSubTitleView.setVisibility(View.VISIBLE);
+ mSubTitleView.setTextColor(t.useLightOnPrimaryColor ?
+ mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor);
+ } else {
+ mSubTitleView.setVisibility(View.GONE);
+ }
mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ?
mLightDismissDrawable : mDarkDismissDrawable);
mDismissButton.setContentDescription(t.dismissDescription);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index afee846..6be9512 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1142,6 +1142,11 @@
}
@Override
+ public void toggleSplitScreen() {
+ toggleSplitScreenMode();
+ }
+
+ @Override
public void preloadRecentApps() {
int msg = MSG_PRELOAD_RECENT_APPS;
mHandler.removeMessages(msg);
@@ -1211,6 +1216,13 @@
}
};
+ /**
+ * Toggle docking the app window
+ *
+ * @return {@code true} if the app window is docked after the toggle, {@code false} otherwise.
+ */
+ protected abstract boolean toggleSplitScreenMode();
+
/** Proxy for RecentsComponent */
protected void showRecents(boolean triggeredFromAltTab) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 3b960ee..6a98488 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -72,6 +72,7 @@
private static final int MSG_ADD_QS_TILE = 27 << MSG_SHIFT;
private static final int MSG_REMOVE_QS_TILE = 28 << MSG_SHIFT;
private static final int MSG_CLICK_QS_TILE = 29 << MSG_SHIFT;
+ private static final int MSG_TOGGLE_APP_SPLIT_SCREEN = 30 << MSG_SHIFT;
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -104,6 +105,7 @@
public void showRecentApps(boolean triggeredFromAltTab);
public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
public void toggleRecentApps();
+ public void toggleSplitScreen();
public void preloadRecentApps();
public void toggleKeyboardShortcutsMenu();
public void cancelPreloadRecentApps();
@@ -223,6 +225,13 @@
}
}
+ public void toggleSplitScreen() {
+ synchronized (mLock) {
+ mHandler.removeMessages(MSG_TOGGLE_APP_SPLIT_SCREEN);
+ mHandler.obtainMessage(MSG_TOGGLE_APP_SPLIT_SCREEN, 0, 0, null).sendToTarget();
+ }
+ }
+
public void toggleRecentApps() {
synchronized (mLock) {
mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS);
@@ -464,6 +473,9 @@
case MSG_CLICK_QS_TILE:
mCallbacks.clickTile((ComponentName) msg.obj);
break;
+ case MSG_TOGGLE_APP_SPLIT_SCREEN:
+ mCallbacks.toggleSplitScreen();
+ break;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index d25e99b..ac714e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1144,31 +1144,42 @@
@Override
public boolean onLongClick(View v) {
- if (mRecents != null) {
- int dockSide = WindowManagerProxy.getInstance().getDockSide();
- if (dockSide == WindowManager.DOCKED_INVALID) {
- Point realSize = new Point();
- mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)
- .getRealSize(realSize);
- Rect initialBounds= new Rect(0, 0, realSize.x, realSize.y);
- boolean docked = mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
- ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
- initialBounds);
- if (docked) {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS);
- return true;
- }
- } else {
- EventBus.getDefault().send(new UndockingTaskEvent());
- MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);
- return true;
- }
-
+ if (mRecents == null) {
+ return false;
+ }
+ boolean initiallyDocked = WindowManagerProxy.getInstance().getDockSide()
+ == WindowManager.DOCKED_INVALID;
+ boolean dockedAtEnd = toggleSplitScreenMode();
+ if (dockedAtEnd != initiallyDocked) {
+ int logAction = dockedAtEnd ? MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS
+ : MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS;
+ MetricsLogger.action(mContext, logAction);
+ return true;
}
return false;
}
};
+ @Override
+ protected boolean toggleSplitScreenMode() {
+ if (mRecents == null) {
+ return false;
+ }
+ int dockSide = WindowManagerProxy.getInstance().getDockSide();
+ if (dockSide == WindowManager.DOCKED_INVALID) {
+ Point realSize = new Point();
+ mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)
+ .getRealSize(realSize);
+ Rect initialBounds= new Rect(0, 0, realSize.x, realSize.y);
+ return mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
+ ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
+ initialBounds);
+ } else {
+ EventBus.getDefault().send(new UndockingTaskEvent());
+ return false;
+ }
+ }
+
private final View.OnLongClickListener mLongPressHomeListener
= new View.OnLongClickListener() {
@Override
@@ -4089,7 +4100,7 @@
ExpandableNotificationRow row = null;
if (expandView instanceof ExpandableNotificationRow) {
row = (ExpandableNotificationRow) expandView;
- row.setUserExpanded(true);
+ row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */);
}
boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
|| !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index 3bd68a9..ab34768 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -80,13 +80,13 @@
// Original is slightly larger than the mirror, so make sure to use the center for the
// positioning.
- int originalX = mInt2Cache[0] + original.getWidth()/2;
- int originalY = mInt2Cache[1];
+ int originalX = mInt2Cache[0] + original.getWidth() / 2;
+ int originalY = mInt2Cache[1] + original.getHeight() / 2;
mBrightnessMirror.setTranslationX(0);
mBrightnessMirror.setTranslationY(0);
mBrightnessMirror.getLocationInWindow(mInt2Cache);
- int mirrorX = mInt2Cache[0] + mBrightnessMirror.getWidth()/2;
- int mirrorY = mInt2Cache[1];
+ int mirrorX = mInt2Cache[0] + mBrightnessMirror.getWidth() / 2;
+ int mirrorY = mInt2Cache[1] + mBrightnessMirror.getHeight() / 2;
mBrightnessMirror.setTranslationX(originalX - mirrorX);
mBrightnessMirror.setTranslationY(originalY - mirrorY);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index e1f9f3c..340ebb4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -1814,8 +1814,12 @@
// it will be set once we reach the boundary
mMaxOverScroll = 0.0f;
}
+ int minScrollY = Math.max(0, scrollRange);
+ if (mExpandedInThisMotion) {
+ minScrollY = Math.min(minScrollY, mMaxScrollAfterExpand);
+ }
mScroller.fling(mScrollX, mOwnScrollY, 1, velocityY, 0, 0, 0,
- Math.max(0, scrollRange), 0, Integer.MAX_VALUE / 2);
+ minScrollY, 0, mExpandedInThisMotion && mOwnScrollY >= 0 ? 0 : Integer.MAX_VALUE / 2);
postInvalidateOnAnimation();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 110258c..0ed6ef8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -116,6 +116,11 @@
}
@Override
+ protected boolean toggleSplitScreenMode() {
+ return false;
+ }
+
+ @Override
public void maybeEscalateHeadsUp() {
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index ec49256..0925638 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -424,9 +424,7 @@
}
Intent intent = new Intent(mContext, PipMenuActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- final ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchStackId(PINNED_STACK_ID);
- mContext.startActivity(intent, options.toBundle());
+ mContext.startActivity(intent);
}
public void addListener(Listener listener) {
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
index 7e229d4..4171dbc 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -33,29 +33,62 @@
private final PipManager mPipManager = PipManager.getInstance();
private MediaController mMediaController;
+ private View mFullButtonView;
+ private View mFullDescriptionView;
+ private View mPlayPauseButtonView;
+ private View mPlayPauseDescriptionView;
+ private View mCloseButtonView;
+ private View mCloseDescriptionView;
+
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.tv_pip_menu);
mPipManager.addListener(this);
- findViewById(R.id.full).setOnClickListener(new View.OnClickListener() {
+ mFullButtonView = findViewById(R.id.full);
+ mFullDescriptionView = findViewById(R.id.full_desc);
+ mFullButtonView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPipManager.movePipToFullscreen();
+ finish();
}
});
- findViewById(R.id.exit).setOnClickListener(new View.OnClickListener() {
+ mFullButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ mFullDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
+ }
+ });
+
+ mPlayPauseButtonView = findViewById(R.id.play_pause);
+ mPlayPauseDescriptionView = findViewById(R.id.play_pause_desc);
+ mPlayPauseButtonView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // TODO: Implement play/pause.
+ }
+ });
+ mPlayPauseButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ mPlayPauseDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
+ }
+ });
+
+ mCloseButtonView = findViewById(R.id.close);
+ mCloseDescriptionView = findViewById(R.id.close_desc);
+ mCloseButtonView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPipManager.closePip();
finish();
}
});
- findViewById(R.id.cancel).setOnClickListener(new View.OnClickListener() {
+ mCloseButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
- public void onClick(View v) {
- mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
- finish();
+ public void onFocusChange(View v, boolean hasFocus) {
+ mCloseDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
index 6f71c92..e5c07d2 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
@@ -17,9 +17,11 @@
package com.android.systemui.tv.pip;
import android.app.Activity;
+import android.graphics.Rect;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
+import android.view.ViewGroup.LayoutParams;
import com.android.systemui.R;
@@ -33,6 +35,8 @@
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.tv_pip_onboarding);
+ View pipOnboardingView = findViewById(R.id.pip_onboarding);
+ View pipOutlineView = findViewById(R.id.pip_outline);
mPipManager.addListener(this);
findViewById(R.id.close).setOnClickListener(new View.OnClickListener() {
@Override
@@ -40,6 +44,20 @@
finish();
}
});
+
+ int pipOutlineSpace = getResources().getDimensionPixelSize(R.dimen.tv_pip_bounds_space);
+ int screenWidth = getResources().getDisplayMetrics().widthPixels;
+ Rect pipBounds = mPipManager.getPipBounds();
+ pipOnboardingView.setPadding(
+ pipBounds.left - pipOutlineSpace,
+ pipBounds.top - pipOutlineSpace,
+ screenWidth - pipBounds.right - pipOutlineSpace, 0);
+
+ // Set width and height for outline view to enclose the PIP.
+ LayoutParams lp = pipOutlineView.getLayoutParams();
+ lp.width = pipBounds.width() + pipOutlineSpace * 2;
+ lp.height = pipBounds.height() + pipOutlineSpace * 2;
+ pipOutlineView.setLayoutParams(lp);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
index 6f24691..cfeab6d 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
@@ -19,8 +19,8 @@
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
-
import android.view.View;
+
import com.android.systemui.R;
/**
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 964688b..c9c5805 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -29,9 +29,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-Iaidl-files-under, src) \
- $(call all-java-files-under, ../src) \
- $(call all-proto-files-under, ../src) \
- src/com/android/systemui/EventLogTags.logtags
+ $(call all-java-files-under, ../src)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
frameworks/support/v7/preference/res \
@@ -53,7 +51,8 @@
android-support-v7-preference \
android-support-v7-appcompat \
android-support-v14-preference \
- android-support-v17-leanback
+ android-support-v17-leanback \
+ SystemUI-proto-tags
# sign this with platform cert, so this test is allowed to inject key events into
# UI it doesn't own. This is necessary to allow screenshots to be taken
diff --git a/packages/SystemUI/tests/src/com/android/systemui/EventLogTags.logtags b/packages/SystemUI/tests/src/com/android/systemui/EventLogTags.logtags
deleted file mode 120000
index 2f243d7..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/EventLogTags.logtags
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../src/com/android/systemui/EventLogTags.logtags
\ No newline at end of file
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 49972d6..568edab 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -447,5 +447,8 @@
// Logs the action the user takes when an app ANR'd.
ACTION_APP_ANR = 317;
+
+ // Logged when a user double taps the overview button to launch the previous task
+ OVERVIEW_LAUNCH_PREVIOUS_TASK = 318;
}
}
diff --git a/services/accessibility/Android.mk b/services/accessibility/Android.mk
index d98fc28..ce89aa7 100644
--- a/services/accessibility/Android.mk
+++ b/services/accessibility/Android.mk
@@ -7,4 +7,6 @@
LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
+LOCAL_JAVA_LIBRARIES := services.core
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 0dbc5be..2b682c5 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -94,6 +94,7 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.server.LocalServices;
+import com.android.server.statusbar.StatusBarManagerInternal;
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileDescriptor;
@@ -2778,6 +2779,9 @@
case AccessibilityService.GLOBAL_ACTION_POWER_DIALOG: {
showGlobalActions();
} return true;
+ case AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN: {
+ toggleSplitScreen();
+ } return true;
}
return false;
} finally {
@@ -3249,6 +3253,10 @@
mWindowManagerService.showGlobalActions();
}
+ private void toggleSplitScreen() {
+ LocalServices.getService(StatusBarManagerInternal.class).toggleSplitScreen();
+ }
+
private IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
if (DEBUG) {
Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
@@ -3465,11 +3473,14 @@
case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
- case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
- case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: {
+ case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: {
return AccessibilityWindowInfo.TYPE_SYSTEM;
}
+ case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: {
+ return AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER;
+ }
+
case WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY: {
return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY;
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index d14364d..caeb0c6 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -660,12 +660,7 @@
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
- synchronized (accounts.cacheLock) {
- if (!accountExistsCacheLocked(accounts, account)) {
- return null;
- }
- return readUserDataInternalLocked(accounts, account, key);
- }
+ return readUserDataInternal(accounts, account, key);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -1717,58 +1712,44 @@
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
- synchronized (accounts.cacheLock) {
- if (!accountExistsCacheLocked(accounts, account)) {
- return;
- }
- setUserdataInternalLocked(accounts, account, key, value);
- }
+ setUserdataInternal(accounts, account, key, value);
} finally {
restoreCallingIdentity(identityToken);
}
}
- private boolean accountExistsCacheLocked(UserAccounts accounts, Account account) {
- if (accounts.accountCache.containsKey(account.type)) {
- for (Account acc : accounts.accountCache.get(account.type)) {
- if (acc.name.equals(account.name)) {
- return true;
- }
- }
- }
- return false;
- }
-
- private void setUserdataInternalLocked(UserAccounts accounts, Account account, String key,
+ private void setUserdataInternal(UserAccounts accounts, Account account, String key,
String value) {
if (account == null || key == null) {
return;
}
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- long accountId = getAccountIdLocked(db, account);
- if (accountId < 0) {
- return;
- }
- long extrasId = getExtrasIdLocked(db, accountId, key);
- if (extrasId < 0) {
- extrasId = insertExtraLocked(db, accountId, key, value);
- if (extrasId < 0) {
+ synchronized (accounts.cacheLock) {
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountIdLocked(db, account);
+ if (accountId < 0) {
return;
}
- } else {
- ContentValues values = new ContentValues();
- values.put(EXTRAS_VALUE, value);
- if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
- return;
- }
+ long extrasId = getExtrasIdLocked(db, accountId, key);
+ if (extrasId < 0 ) {
+ extrasId = insertExtraLocked(db, accountId, key, value);
+ if (extrasId < 0) {
+ return;
+ }
+ } else {
+ ContentValues values = new ContentValues();
+ values.put(EXTRAS_VALUE, value);
+ if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
+ return;
+ }
+ }
+ writeUserDataIntoCacheLocked(accounts, db, account, key, value);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
}
- writeUserDataIntoCacheLocked(accounts, db, account, key, value);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
}
}
@@ -4803,16 +4784,17 @@
}
}
- protected String readUserDataInternalLocked(
- UserAccounts accounts, Account account, String key) {
- HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
- if (userDataForAccount == null) {
- // need to populate the cache for this account
- final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
- userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
- accounts.userDataCache.put(account, userDataForAccount);
+ protected String readUserDataInternal(UserAccounts accounts, Account account, String key) {
+ synchronized (accounts.cacheLock) {
+ HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
+ if (userDataForAccount == null) {
+ // need to populate the cache for this account
+ final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
+ userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
+ accounts.userDataCache.put(account, userDataForAccount);
+ }
+ return userDataForAccount.get(key);
}
- return userDataForAccount.get(key);
}
protected HashMap<String, String> readUserDataForAccountFromDatabaseLocked(
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 536c75e..4bf77d3 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -1146,7 +1146,8 @@
final ComponentName service = job.getService();
try {
ServiceInfo si = pm.getServiceInfo(service,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(uid));
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
+ UserHandle.getUserId(uid));
if (si == null) {
throw new IllegalArgumentException("No such service " + service);
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index dd13809..1652185 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2387,10 +2387,7 @@
if (DEBUG_KERNEL) Slog.d(TAG, "Dropping mapping " + name);
mKernelMapping.remove(name);
-
- final File dir = new File(mKernelMappingFilename, name);
- FileUtils.deleteContents(dir);
- dir.delete();
+ new File(mKernelMappingFilename, name).delete();
}
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index cbbcdae..6bda4ed 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -33,4 +33,5 @@
void topAppWindowChanged(boolean menuVisible);
void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
Rect fullscreenBounds, Rect dockedBounds, String cause);
+ void toggleSplitScreen();
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 6eab8d4..d24e1af 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -204,6 +204,16 @@
StatusBarManagerService.this.setSystemUiVisibility(vis, fullscreenStackVis,
dockedStackVis, mask, fullscreenBounds, dockedBounds, cause);
}
+
+ @Override
+ public void toggleSplitScreen() {
+ enforceStatusBarService();
+ if (mBar != null) {
+ try {
+ mBar.toggleSplitScreen();
+ } catch (RemoteException ex) {}
+ }
+ }
};
// ================================================================================
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index e39445a..c97323c 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -29,10 +29,11 @@
#include "android_runtime/Log.h"
#include <arpa/inet.h>
-#include <string.h>
-#include <pthread.h>
+#include <limits>
#include <linux/in.h>
#include <linux/in6.h>
+#include <pthread.h>
+#include <string.h>
static jobject mCallbacksObj = NULL;
@@ -1090,11 +1091,37 @@
if (flags & (flag)) object.callSetter("set" # setter, (value))
static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
+ static uint32_t discontinuity_count_to_handle_old_lock_type = 0;
JavaObject object(env, "android/location/GnssClock");
GpsClockFlags flags = clock->flags;
SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
- SET(Type, clock->type);
+
+ // GnssClock only supports the more effective HW_CLOCK type, so type
+ // handling and documentation complexity has been removed. To convert the
+ // old GPS_CLOCK types (active only in a limited number of older devices),
+ // the GPS time information is handled as an always discontinuous HW clock,
+ // with the GPS time information put into the full_bias_ns instead - so that
+ // time_ns + full_bias_ns = local estimate of GPS time (as remains true, in
+ // the new GnssClock struct.)
+ switch (clock->type) {
+ case GPS_CLOCK_TYPE_UNKNOWN:
+ // Clock type unsupported.
+ ALOGE("Unknown clock type provided.");
+ break;
+ case GPS_CLOCK_TYPE_LOCAL_HW_TIME:
+ // Already local hardware time. No need to do anything.
+ break;
+ case GPS_CLOCK_TYPE_GPS_TIME:
+ // GPS time, need to convert.
+ flags |= GNSS_CLOCK_HAS_FULL_BIAS;
+ clock->full_bias_ns = clock->time_ns;
+ clock->time_ns = 0;
+ SET(HardwareClockDiscontinuityCount,
+ discontinuity_count_to_handle_old_lock_type++);
+ break;
+ }
+
SET(TimeInNs, clock->time_ns);
SET_IF(GNSS_CLOCK_HAS_TIME_UNCERTAINTY,
TimeUncertaintyInNs,
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index 4aa5b98..558c1dc 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -241,6 +241,16 @@
public static final int CODE_ANSWERED_ELSEWHERE = 1014;
/**
+ * Call pull request failure from the network.
+ */
+ public static final int CODE_CALL_PULL_OUT_OF_SYNC = 1015;
+
+ /**
+ * Call ended due to being pulled onto another device.
+ */
+ public static final int CODE_CALL_END_CAUSE_CALL_PULL = 1016;
+
+ /**
* Supplementary services (HOLD/RESUME) failure error codes.
* Values for Supplemetary services failure - Failed, Cancelled and Re-Invite collision.
*/
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 8b8d604..4bed941 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -60,6 +60,8 @@
// optional parameter: comma separated list of required account types before proceeding
// with the app launch
private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
+ private static final String WEARABLE_ACTION_GOOGLE =
+ "com.google.android.wearable.action.GOOGLE";
private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 7500; //7.5s to allow app to idle
private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches
private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 2000; //2s between launching apps
@@ -183,6 +185,13 @@
Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);
+ resolveLoop(ris, intentToResolve, pm);
+ intentToResolve = new Intent(WEARABLE_ACTION_GOOGLE);
+ ris = pm.queryIntentActivities(intentToResolve, 0);
+ resolveLoop(ris, intentToResolve, pm);
+ }
+
+ private void resolveLoop(List<ResolveInfo> ris, Intent intentToResolve, PackageManager pm) {
if (ris == null || ris.isEmpty()) {
Log.i(TAG, "Could not find any apps");
} else {
diff --git a/tests/UiBench/res/layout/activity_transition.xml b/tests/UiBench/res/layout/activity_transition.xml
index d4c6610..4556b02 100644
--- a/tests/UiBench/res/layout/activity_transition.xml
+++ b/tests/UiBench/res/layout/activity_transition.xml
@@ -15,6 +15,7 @@
~ limitations under the License
-->
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/transition_grid_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="true"
@@ -25,8 +26,6 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:scaleType="centerCrop"
- android:layout_column="0"
- android:layout_row="0"
android:src="@drawable/ducky"
android:onClick="clicked"
android:transitionName="ducky"/>
@@ -36,8 +35,6 @@
android:layout_width="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/woot"
- android:layout_column="1"
- android:layout_row="0"
android:onClick="clicked"
android:transitionName="woot"/>
<ImageView
@@ -46,8 +43,6 @@
android:layout_width="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/ball"
- android:layout_column="0"
- android:layout_row="1"
android:onClick="clicked"
android:transitionName="ball"/>
<ImageView
@@ -56,8 +51,6 @@
android:layout_width="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/block"
- android:layout_column="1"
- android:layout_row="1"
android:onClick="clicked"
android:transitionName="block"/>
<ImageView
@@ -66,8 +59,6 @@
android:layout_width="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/jellies"
- android:layout_column="0"
- android:layout_row="2"
android:onClick="clicked"
android:transitionName="jellies"/>
<ImageView
@@ -76,8 +67,6 @@
android:layout_width="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/mug"
- android:layout_column="1"
- android:layout_row="2"
android:onClick="clicked"
android:transitionName="mug"/>
<ImageView
@@ -86,8 +75,6 @@
android:layout_width="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/pencil"
- android:layout_column="0"
- android:layout_row="3"
android:onClick="clicked"
android:transitionName="pencil"/>
<ImageView
@@ -96,8 +83,6 @@
android:layout_width="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/scissors"
- android:layout_column="1"
- android:layout_row="3"
android:onClick="clicked"
android:transitionName="scissors"/>
</GridLayout>
\ No newline at end of file
diff --git a/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java b/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java
index 1106a13..0a069c2 100644
--- a/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java
+++ b/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java
@@ -18,11 +18,13 @@
import android.app.ActivityOptions;
import android.app.SharedElementCallback;
import android.content.Intent;
+import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
+import android.widget.GridLayout;
import android.widget.ImageView;
import java.util.List;
@@ -90,6 +92,13 @@
getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
setContentView(R.layout.activity_transition);
setupHero();
+
+ // Ensure that all images are visible regardless of orientation.
+ GridLayout gridLayout = (GridLayout) findViewById(R.id.transition_grid_layout);
+ boolean isPortrait =
+ getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
+ gridLayout.setRowCount(isPortrait ? 4 : 2);
+ gridLayout.setColumnCount(isPortrait ? 2 : 4);
}
private void setupHero() {