Merge "Add Dialog list, shadow, inflation tests"
diff --git a/Android.mk b/Android.mk
index 40da134..e84b683 100644
--- a/Android.mk
+++ b/Android.mk
@@ -160,6 +160,7 @@
core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl \
core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl \
core/java/android/hardware/fingerprint/IFingerprintService.aidl \
+ core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl \
core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl \
core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \
core/java/android/hardware/hdmi/IHdmiControlService.aidl \
diff --git a/api/current.txt b/api/current.txt
index e9c5727..b296672 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9663,12 +9663,14 @@
method public int diff(android.content.res.Configuration);
method public boolean equals(android.content.res.Configuration);
method public int getLayoutDirection();
+ method public android.util.LocaleList getLocales();
method public boolean isLayoutSizeAtLeast(int);
method public boolean isScreenRound();
method public static boolean needNewResources(int, int);
method public void readFromParcel(android.os.Parcel);
method public void setLayoutDirection(java.util.Locale);
method public void setLocale(java.util.Locale);
+ method public void setLocales(android.util.LocaleList);
method public void setTo(android.content.res.Configuration);
method public void setToDefaults();
method public int updateFrom(android.content.res.Configuration);
@@ -9742,7 +9744,7 @@
field public int hardKeyboardHidden;
field public int keyboard;
field public int keyboardHidden;
- field public java.util.Locale locale;
+ field public deprecated java.util.Locale locale;
field public int mcc;
field public int mnc;
field public int navigation;
@@ -18164,6 +18166,7 @@
method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
+ method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
method public android.mtp.MtpObjectInfo.Builder setParent(int);
method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
@@ -34200,11 +34203,15 @@
public final class LocaleList {
ctor public LocaleList();
+ ctor public LocaleList(java.util.Locale);
ctor public LocaleList(java.util.Locale[]);
+ method public static android.util.LocaleList forLanguageTags(java.lang.String);
method public java.util.Locale get(int);
+ method public static android.util.LocaleList getEmptyLocaleList();
method public java.util.Locale getPrimary();
method public boolean isEmpty();
method public int size();
+ method public java.lang.String toLanguageTags();
}
public final class Log {
diff --git a/api/system-current.txt b/api/system-current.txt
index e234970..7cc66cf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -10000,12 +10000,14 @@
method public int diff(android.content.res.Configuration);
method public boolean equals(android.content.res.Configuration);
method public int getLayoutDirection();
+ method public android.util.LocaleList getLocales();
method public boolean isLayoutSizeAtLeast(int);
method public boolean isScreenRound();
method public static boolean needNewResources(int, int);
method public void readFromParcel(android.os.Parcel);
method public void setLayoutDirection(java.util.Locale);
method public void setLocale(java.util.Locale);
+ method public void setLocales(android.util.LocaleList);
method public void setTo(android.content.res.Configuration);
method public void setToDefaults();
method public int updateFrom(android.content.res.Configuration);
@@ -10079,7 +10081,7 @@
field public int hardKeyboardHidden;
field public int keyboard;
field public int keyboardHidden;
- field public java.util.Locale locale;
+ field public deprecated java.util.Locale locale;
field public int mcc;
field public int mnc;
field public int navigation;
@@ -19676,6 +19678,7 @@
method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
+ method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
method public android.mtp.MtpObjectInfo.Builder setParent(int);
method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
@@ -36494,11 +36497,15 @@
public final class LocaleList {
ctor public LocaleList();
+ ctor public LocaleList(java.util.Locale);
ctor public LocaleList(java.util.Locale[]);
+ method public static android.util.LocaleList forLanguageTags(java.lang.String);
method public java.util.Locale get(int);
+ method public static android.util.LocaleList getEmptyLocaleList();
method public java.util.Locale getPrimary();
method public boolean isEmpty();
method public int size();
+ method public java.lang.String toLanguageTags();
}
public final class Log {
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 3b026d2..132ffef 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -2196,6 +2196,7 @@
fragment.mTag = tag;
fragment.mInLayout = true;
fragment.mFragmentManager = this;
+ fragment.mHost = mHost;
fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);
addFragment(fragment, true);
} else if (fragment.mInLayout) {
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6feb860..914945b 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -531,12 +531,14 @@
/**
* String retrieved from the seinfo tag found in selinux policy. This value
- * is useful in setting an SELinux security context on the process as well
- * as its data directory.
+ * can be overridden with a value set through the mac_permissions.xml policy
+ * construct. This value is useful in setting an SELinux security context on
+ * the process as well as its data directory. The String default is being used
+ * here to represent a catchall label when no policy matches.
*
* {@hide}
*/
- public String seinfo;
+ public String seinfo = "default";
/**
* Paths to all shared libraries this application is linked against. This
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index fd60476..3ecbaa0 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -22,11 +22,13 @@
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import android.annotation.Nullable;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import android.util.LocaleList;
import android.view.View;
import java.io.IOException;
@@ -36,7 +38,7 @@
/**
* This class describes all device configuration information that can
* impact the resources the application retrieves. This includes both
- * user-specified configuration options (locale and scaling) as well
+ * user-specified configuration options (locale list and scaling) as well
* as device configurations (such as input modes, screen size and screen orientation).
* <p>You can acquire this object from {@link Resources}, using {@link
* Resources#getConfiguration}. Thus, from an activity, you can get it by chaining the request
@@ -78,8 +80,13 @@
* Current user preference for the locale, corresponding to
* <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a>
* resource qualifier.
+ *
+ * @deprecated Do not set or read this directly. Use {@link #getLocales()} and
+ * {@link #setLocales(LocaleList)}.
*/
- public Locale locale;
+ @Deprecated public Locale locale;
+
+ private LocaleList mLocaleList;
/**
* Locale should persist on setting. This is hidden because it is really
@@ -648,6 +655,15 @@
setTo(o);
}
+ /* This brings mLocaleList in sync with locale in case a user of the older API who doesn't know
+ * about setLocales() has changed locale directly. */
+ private void fixUpLocaleList() {
+ if ((locale == null && !mLocaleList.isEmpty()) ||
+ (locale != null && !locale.equals(mLocaleList.getPrimary()))) {
+ mLocaleList = new LocaleList(locale);
+ }
+ }
+
public void setTo(Configuration o) {
fontScale = o.fontScale;
mcc = o.mcc;
@@ -655,6 +671,8 @@
if (o.locale != null) {
locale = (Locale) o.locale.clone();
}
+ o.fixUpLocaleList();
+ mLocaleList = o.mLocaleList;
userSetLocale = o.userSetLocale;
touchscreen = o.touchscreen;
keyboard = o.keyboard;
@@ -692,11 +710,12 @@
} else {
sb.append("?mnc");
}
- if (locale != null) {
+ fixUpLocaleList();
+ if (!mLocaleList.isEmpty()) {
sb.append(" ");
- sb.append(locale);
+ sb.append(mLocaleList);
} else {
- sb.append(" ?locale");
+ sb.append(" ?localeList");
}
int layoutDir = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK);
switch (layoutDir) {
@@ -819,6 +838,7 @@
public void setToDefaults() {
fontScale = 1;
mcc = mnc = 0;
+ mLocaleList = LocaleList.getEmptyLocaleList();
locale = null;
userSetLocale = false;
touchscreen = TOUCHSCREEN_UNDEFINED;
@@ -864,16 +884,20 @@
changed |= ActivityInfo.CONFIG_MNC;
mnc = delta.mnc;
}
- if (delta.locale != null
- && (locale == null || !locale.equals(delta.locale))) {
+ fixUpLocaleList();
+ delta.fixUpLocaleList();
+ if (!delta.mLocaleList.isEmpty() && !mLocaleList.equals(delta.mLocaleList)) {
changed |= ActivityInfo.CONFIG_LOCALE;
- locale = delta.locale != null
- ? (Locale) delta.locale.clone() : null;
- // If locale has changed, then layout direction is also changed ...
- changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
- // ... and we need to update the layout direction (represented by the first
- // 2 most significant bits in screenLayout).
- setLayoutDirection(locale);
+ mLocaleList = delta.mLocaleList;
+ // delta.locale can't be null, since delta.mLocaleList is not empty.
+ if (!delta.locale.equals(locale)) {
+ locale = (Locale) delta.locale.clone();
+ // If locale has changed, then layout direction is also changed ...
+ changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
+ // ... and we need to update the layout direction (represented by the first
+ // 2 most significant bits in screenLayout).
+ setLayoutDirection(locale);
+ }
}
final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
if (deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED &&
@@ -1023,8 +1047,9 @@
if (delta.mnc != 0 && mnc != delta.mnc) {
changed |= ActivityInfo.CONFIG_MNC;
}
- if (delta.locale != null
- && (locale == null || !locale.equals(delta.locale))) {
+ fixUpLocaleList();
+ delta.fixUpLocaleList();
+ if (!mLocaleList.equals(delta.mLocaleList)) {
changed |= ActivityInfo.CONFIG_LOCALE;
changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
}
@@ -1146,14 +1171,15 @@
dest.writeFloat(fontScale);
dest.writeInt(mcc);
dest.writeInt(mnc);
- if (locale == null) {
- dest.writeInt(0);
- } else {
- dest.writeInt(1);
- dest.writeString(locale.getLanguage());
- dest.writeString(locale.getCountry());
- dest.writeString(locale.getVariant());
+
+ fixUpLocaleList();
+ final int localeListSize = mLocaleList.size();
+ dest.writeInt(localeListSize);
+ for (int i = 0; i < localeListSize; ++i) {
+ final Locale l = mLocaleList.get(i);
+ dest.writeString(l.toLanguageTag());
}
+
if(userSetLocale) {
dest.writeInt(1);
} else {
@@ -1182,10 +1208,15 @@
fontScale = source.readFloat();
mcc = source.readInt();
mnc = source.readInt();
- if (source.readInt() != 0) {
- locale = new Locale(source.readString(), source.readString(),
- source.readString());
+
+ final int localeListSize = source.readInt();
+ final Locale[] localeArray = new Locale[localeListSize];
+ for (int i = 0; i < localeListSize; ++i) {
+ localeArray[i] = Locale.forLanguageTag(source.readString());
}
+ mLocaleList = new LocaleList(localeArray);
+ locale = mLocaleList.getPrimary();
+
userSetLocale = (source.readInt()==1);
touchscreen = source.readInt();
keyboard = source.readInt();
@@ -1234,18 +1265,33 @@
if (n != 0) return n;
n = this.mnc - that.mnc;
if (n != 0) return n;
- if (this.locale == null) {
- if (that.locale != null) return 1;
- } else if (that.locale == null) {
+
+ fixUpLocaleList();
+ that.fixUpLocaleList();
+ // for backward compatibility, we consider an empty locale list to be greater
+ // than any non-empty locale list.
+ if (this.mLocaleList.isEmpty()) {
+ if (!that.mLocaleList.isEmpty()) return 1;
+ } else if (that.mLocaleList.isEmpty()) {
return -1;
} else {
- n = this.locale.getLanguage().compareTo(that.locale.getLanguage());
- if (n != 0) return n;
- n = this.locale.getCountry().compareTo(that.locale.getCountry());
- if (n != 0) return n;
- n = this.locale.getVariant().compareTo(that.locale.getVariant());
+ final int minSize = Math.min(this.mLocaleList.size(), that.mLocaleList.size());
+ for (int i = 0; i < minSize; ++i) {
+ final Locale thisLocale = this.mLocaleList.get(i);
+ final Locale thatLocale = that.mLocaleList.get(i);
+ n = thisLocale.getLanguage().compareTo(thatLocale.getLanguage());
+ if (n != 0) return n;
+ n = thisLocale.getCountry().compareTo(thatLocale.getCountry());
+ if (n != 0) return n;
+ n = thisLocale.getVariant().compareTo(thatLocale.getVariant());
+ if (n != 0) return n;
+ n = thisLocale.toLanguageTag().compareTo(thatLocale.toLanguageTag());
+ if (n != 0) return n;
+ }
+ n = this.mLocaleList.size() - that.mLocaleList.size();
if (n != 0) return n;
}
+
n = this.touchscreen - that.touchscreen;
if (n != 0) return n;
n = this.keyboard - that.keyboard;
@@ -1288,13 +1334,13 @@
}
return false;
}
-
+
public int hashCode() {
int result = 17;
result = 31 * result + Float.floatToIntBits(fontScale);
result = 31 * result + mcc;
result = 31 * result + mnc;
- result = 31 * result + (locale != null ? locale.hashCode() : 0);
+ result = 31 * result + mLocaleList.hashCode();
result = 31 * result + touchscreen;
result = 31 * result + keyboard;
result = 31 * result + keyboardHidden;
@@ -1312,14 +1358,47 @@
}
/**
- * Set the locale. This is the preferred way for setting up the locale (instead of using the
- * direct accessor). This will also set the layout direction according to the locale.
+ * Get the locale list. This is the preferred way for getting the locales (instead of using
+ * the direct accessor to {@link #locale}, which would only provide the primary locale).
+ *
+ * @return The locale list.
+ */
+ public LocaleList getLocales() {
+ fixUpLocaleList();
+ return mLocaleList;
+ }
+
+ /**
+ * Set the locale list. This is the preferred way for setting up the locales (instead of using
+ * the direct accessor or {@link #setLocale(Locale)}). This will also set the layout direction
+ * according to the first locale in the list.
+ *
+ * Note that the layout direction will always come from the first locale in the locale list,
+ * even if the locale is not supported by the resources (the resources may only support
+ * another locale further down the list which has a different direction).
+ *
+ * @param locales The locale list. If null, an empty LocaleList will be assigned.
+ */
+ public void setLocales(@Nullable LocaleList locales) {
+ mLocaleList = locales == null ? LocaleList.getEmptyLocaleList() : locales;
+ locale = mLocaleList.getPrimary();
+ setLayoutDirection(locale);
+ }
+
+ /**
+ * Set the locale list to a list of just one locale. This will also set the layout direction
+ * according to the locale.
+ *
+ * Note that after this is run, calling <code>.equals()</code> on the input locale and the
+ * {@link #locale} attribute would return <code>true</code> if they are not null, but there is
+ * no guarantee that they would be the same object.
+ *
+ * See also the note about layout direction in {@link #setLocales(LocaleList)}.
*
* @param loc The locale. Can be null.
*/
- public void setLocale(Locale loc) {
- locale = loc;
- setLayoutDirection(locale);
+ public void setLocale(@Nullable Locale loc) {
+ setLocales(new LocaleList(loc));
}
/**
@@ -1335,19 +1414,19 @@
}
/**
- * Set the layout direction from the Locale.
+ * Set the layout direction from a Locale.
*
- * @param locale The Locale. If null will set the layout direction to
+ * @param loc The Locale. If null will set the layout direction to
* {@link View#LAYOUT_DIRECTION_LTR}. If not null will set it to the layout direction
* corresponding to the Locale.
*
* @see View#LAYOUT_DIRECTION_LTR
* @see View#LAYOUT_DIRECTION_RTL
*/
- public void setLayoutDirection(Locale locale) {
+ public void setLayoutDirection(Locale loc) {
// There is a "1" difference between the configuration values for
// layout direction and View constants for layout direction, just add "1".
- final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(locale);
+ final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(loc);
screenLayout = (screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK)|
(layoutDirection << SCREENLAYOUT_LAYOUTDIR_SHIFT);
}
@@ -1370,21 +1449,21 @@
*
* @hide
*/
- public static String localeToResourceQualifier(Locale locale) {
+ public static String localeToResourceQualifier(Locale loc) {
StringBuilder sb = new StringBuilder();
- boolean l = (locale.getLanguage().length() != 0);
- boolean c = (locale.getCountry().length() != 0);
- boolean s = (locale.getScript().length() != 0);
- boolean v = (locale.getVariant().length() != 0);
-
+ boolean l = (loc.getLanguage().length() != 0);
+ boolean c = (loc.getCountry().length() != 0);
+ boolean s = (loc.getScript().length() != 0);
+ boolean v = (loc.getVariant().length() != 0);
+ // TODO: take script and extensions into account
if (l) {
- sb.append(locale.getLanguage());
+ sb.append(loc.getLanguage());
if (c) {
- sb.append("-r").append(locale.getCountry());
+ sb.append("-r").append(loc.getCountry());
if (s) {
- sb.append("-s").append(locale.getScript());
+ sb.append("-s").append(loc.getScript());
if (v) {
- sb.append("-v").append(locale.getVariant());
+ sb.append("-v").append(loc.getVariant());
}
}
}
@@ -1409,6 +1488,7 @@
}
}
+ // TODO: send the whole locale list
if (config.locale != null && !config.locale.getLanguage().isEmpty()) {
parts.add(localeToResourceQualifier(config.locale));
}
@@ -1646,8 +1726,10 @@
delta.mnc = change.mnc;
}
- if ((base.locale == null && change.locale != null) ||
- (base.locale != null && !base.locale.equals(change.locale))) {
+ base.fixUpLocaleList();
+ change.fixUpLocaleList();
+ if (!base.mLocaleList.equals(change.mLocaleList)) {
+ delta.mLocaleList = change.mLocaleList;
delta.locale = change.locale;
}
@@ -1724,7 +1806,7 @@
private static final String XML_ATTR_FONT_SCALE = "fs";
private static final String XML_ATTR_MCC = "mcc";
private static final String XML_ATTR_MNC = "mnc";
- private static final String XML_ATTR_LOCALE = "locale";
+ private static final String XML_ATTR_LOCALES = "locales";
private static final String XML_ATTR_TOUCHSCREEN = "touch";
private static final String XML_ATTR_KEYBOARD = "key";
private static final String XML_ATTR_KEYBOARD_HIDDEN = "keyHid";
@@ -1754,10 +1836,9 @@
configOut.mcc = XmlUtils.readIntAttribute(parser, XML_ATTR_MCC, 0);
configOut.mnc = XmlUtils.readIntAttribute(parser, XML_ATTR_MNC, 0);
- final String localeStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALE);
- if (localeStr != null) {
- configOut.locale = Locale.forLanguageTag(localeStr);
- }
+ final String localesStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALES);
+ configOut.mLocaleList = LocaleList.forLanguageTags(localesStr);
+ configOut.locale = configOut.mLocaleList.getPrimary();
configOut.touchscreen = XmlUtils.readIntAttribute(parser, XML_ATTR_TOUCHSCREEN,
TOUCHSCREEN_UNDEFINED);
@@ -1807,8 +1888,9 @@
if (config.mnc != 0) {
XmlUtils.writeIntAttribute(xml, XML_ATTR_MNC, config.mnc);
}
- if (config.locale != null) {
- XmlUtils.writeStringAttribute(xml, XML_ATTR_LOCALE, config.locale.toLanguageTag());
+ config.fixUpLocaleList();
+ if (!config.mLocaleList.isEmpty()) {
+ XmlUtils.writeStringAttribute(xml, XML_ATTR_LOCALES, config.mLocaleList.toLanguageTags());
}
if (config.touchscreen != TOUCHSCREEN_UNDEFINED) {
XmlUtils.writeIntAttribute(xml, XML_ATTR_TOUCHSCREEN, config.touchscreen);
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 7cff11b..1f23c0a 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -392,6 +392,18 @@
};
/**
+ * @hide
+ */
+ public static abstract class LockoutResetCallback {
+
+ /**
+ * Called when lockout period expired and clients are allowed to listen for fingerprint
+ * again.
+ */
+ public void onLockoutReset() { }
+ };
+
+ /**
* Request authentication of a crypto object. This call warms up the fingerprint hardware
* and starts scanning for a fingerprint. It terminates when
* {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
@@ -680,10 +692,37 @@
try {
mService.resetTimeout(token);
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in getAuthenticatorId(): ", e);
+ Log.v(TAG, "Remote exception in resetTimeout(): ", e);
}
} else {
- Log.w(TAG, "getAuthenticatorId(): Service not connected!");
+ Log.w(TAG, "resetTimeout(): Service not connected!");
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void addLockoutResetCallback(final LockoutResetCallback callback) {
+ if (mService != null) {
+ try {
+ mService.addLockoutResetCallback(
+ new IFingerprintServiceLockoutResetCallback.Stub() {
+
+ @Override
+ public void onLockoutReset(long deviceId) throws RemoteException {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onLockoutReset();
+ }
+ });
+ }
+ });
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in addLockoutResetCallback(): ", e);
+ }
+ } else {
+ Log.w(TAG, "addLockoutResetCallback(): Service not connected!");
}
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 3356354..690a751 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -17,6 +17,7 @@
import android.os.Bundle;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
import android.hardware.fingerprint.Fingerprint;
import java.util.List;
@@ -71,4 +72,7 @@
// Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password)
void resetTimeout(in byte [] cryptoToken);
+
+ // Add a callback which gets notified when the fingerprint lockout period expired.
+ void addLockoutResetCallback(IFingerprintServiceLockoutResetCallback callback);
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
new file mode 100644
index 0000000..c9a5d59
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.fingerprint;
+
+import android.hardware.fingerprint.Fingerprint;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+/**
+ * Callback when lockout period expired and clients are allowed to authenticate again.
+ * @hide
+ */
+oneway interface IFingerprintServiceLockoutResetCallback {
+ void onLockoutReset(long deviceId);
+}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 444f020..4292050 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -291,6 +291,7 @@
}
synchronized (mInputDevicesLock) {
+ populateInputDevicesLocked();
int index = findInputDeviceListenerLocked(listener);
if (index < 0) {
mInputDeviceListeners.add(new InputDeviceListenerDelegate(listener, handler));
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 4ad9d6d..bad94fc 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -468,6 +468,7 @@
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
* @see BatteryStats#getCpuSpeedSteps()
*/
+ @Deprecated
public abstract long getTimeAtCpuSpeed(int step, int which);
public static abstract class Sensor {
diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java
index 017735a..afae9ac 100644
--- a/core/java/android/util/LocaleList.java
+++ b/core/java/android/util/LocaleList.java
@@ -23,8 +23,8 @@
// TODO: We don't except too many LocaleLists to exist at the same time, and
// we need access to the data at native level, so we should pass the data
-// down to the native level, create a mapt of every list seen there, take a
-// pointer back, and just keep that pointed in the Java-level object, so
+// down to the native level, create a map of every list seen there, take a
+// pointer back, and just keep that pointer in the Java-level object, so
// things could be copied very quickly.
/**
@@ -34,6 +34,7 @@
public final class LocaleList {
private final Locale[] mList;
private static final Locale[] sEmptyList = new Locale[0];
+ private static final LocaleList sEmptyLocaleList = new LocaleList();
public Locale get(int location) {
return location < mList.length ? mList[location] : null;
@@ -51,6 +52,60 @@
return mList.length;
}
+ @Override
+ public boolean equals(Object other) {
+ if (other == this)
+ return true;
+ if (!(other instanceof LocaleList))
+ return false;
+ final Locale[] otherList = ((LocaleList) other).mList;
+ if (mList.length != otherList.length)
+ return false;
+ for (int i = 0; i < mList.length; ++i) {
+ if (!mList[i].equals(otherList[i]))
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 1;
+ for (int i = 0; i < mList.length; ++i) {
+ result = 31 * result + mList[i].hashCode();
+ }
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ for (int i = 0; i < mList.length; ++i) {
+ sb.append(mList[i]);
+ if (i < mList.length - 1) {
+ sb.append(',');
+ }
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ public String toLanguageTags() {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < mList.length; ++i) {
+ sb.append(mList[i].toLanguageTag());
+ if (i < mList.length - 1) {
+ sb.append(',');
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * It is almost always better to call {@link #getEmptyLocaleList()} instead which returns
+ * a pre-constructed empty locale list.
+ */
public LocaleList() {
mList = sEmptyList;
}
@@ -59,6 +114,19 @@
* @throws NullPointerException if any of the input locales is <code>null</code>.
* @throws IllegalArgumentException if any of the input locales repeat.
*/
+ public LocaleList(@Nullable Locale locale) {
+ if (locale == null) {
+ mList = sEmptyList;
+ } else {
+ mList = new Locale[1];
+ mList[0] = (Locale) locale.clone();
+ }
+ }
+
+ /**
+ * @throws NullPointerException if any of the input locales is <code>null</code>.
+ * @throws IllegalArgumentException if any of the input locales repeat.
+ */
public LocaleList(@Nullable Locale[] list) {
if (list == null || list.length == 0) {
mList = sEmptyList;
@@ -79,4 +147,21 @@
mList = localeList;
}
}
+
+ public static LocaleList getEmptyLocaleList() {
+ return sEmptyLocaleList;
+ }
+
+ public static LocaleList forLanguageTags(@Nullable String list) {
+ if (list == null || list.equals("")) {
+ return getEmptyLocaleList();
+ } else {
+ final String[] tags = list.split(",");
+ final Locale[] localeArray = new Locale[tags.length];
+ for (int i = 0; i < localeArray.length; ++i) {
+ localeArray[i] = Locale.forLanguageTag(tags[i]);
+ }
+ return new LocaleList(localeArray);
+ }
+ }
}
diff --git a/core/java/android/view/HandlerActionQueue.java b/core/java/android/view/HandlerActionQueue.java
new file mode 100644
index 0000000..4758a34
--- /dev/null
+++ b/core/java/android/view/HandlerActionQueue.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import com.android.internal.util.GrowingArrayUtils;
+
+import android.os.Handler;
+
+import java.util.ArrayList;
+
+/**
+ * Class used to enqueue pending work from Views when no Handler is attached.
+ *
+ * @hide Exposed for test framework only.
+ */
+public class HandlerActionQueue {
+ private HandlerAction[] mActions;
+ private int mCount;
+
+ public void post(Runnable action) {
+ postDelayed(action, 0);
+ }
+
+ public void postDelayed(Runnable action, long delayMillis) {
+ final HandlerAction handlerAction = new HandlerAction(action, delayMillis);
+
+ synchronized (this) {
+ if (mActions == null) {
+ mActions = new HandlerAction[4];
+ }
+ mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
+ mCount++;
+ }
+ }
+
+ public void removeCallbacks(Runnable action) {
+ synchronized (this) {
+ final int count = mCount;
+ int j = 0;
+
+ final HandlerAction[] actions = mActions;
+ for (int i = 0; i < count; i++) {
+ if (actions[i].matches(action)) {
+ // Remove this action by overwriting it within
+ // this loop or nulling it out later.
+ continue;
+ }
+
+ if (j != i) {
+ // At least one previous entry was removed, so
+ // this one needs to move to the "new" list.
+ actions[j] = actions[i];
+ }
+
+ j++;
+ }
+
+ // The "new" list only has j entries.
+ mCount = j;
+
+ // Null out any remaining entries.
+ for (; j < count; j++) {
+ actions[j] = null;
+ }
+ }
+ }
+
+ public void executeActions(Handler handler) {
+ synchronized (this) {
+ final HandlerAction[] actions = mActions;
+ for (int i = 0, count = mCount; i < count; i++) {
+ final HandlerAction handlerAction = actions[i];
+ handler.postDelayed(handlerAction.action, handlerAction.delay);
+ }
+
+ mActions = null;
+ mCount = 0;
+ }
+ }
+
+ public int size() {
+ return mCount;
+ }
+
+ public Runnable getRunnable(int index) {
+ if (index >= mCount) {
+ throw new IndexOutOfBoundsException();
+ }
+ return mActions[index].action;
+ }
+
+ public long getDelay(int index) {
+ if (index >= mCount) {
+ throw new IndexOutOfBoundsException();
+ }
+ return mActions[index].delay;
+ }
+
+ private static class HandlerAction {
+ final Runnable action;
+ final long delay;
+
+ public HandlerAction(Runnable action, long delay) {
+ this.action = action;
+ this.delay = delay;
+ }
+
+ public boolean matches(Runnable otherAction) {
+ return otherAction == null && action == null
+ || action != null && action.equals(otherAction);
+ }
+ }
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index f86adfe..33c51ff 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -97,21 +97,21 @@
* @param launchTaskBehind True if the token is been launched from behind.
* @param taskBounds Bounds to use when creating a new Task with the input task Id if
* the task doesn't exist yet.
- * @return The configuration of the task if it was newly created. null otherwise.
+ * @param configuration Configuration that is being used with this task.
*/
- Configuration addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
+ void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
- in Rect taskBounds);
+ in Rect taskBounds, in Configuration configuration);
/**
*
* @param token The token we are adding to the input task Id.
* @param taskId The Id of the task we are adding the token to.
* @param taskBounds Bounds to use when creating a new Task with the input task Id if
* the task doesn't exist yet.
- * @return The configuration of the task if it was newly created. null otherwise.
+ * @param config Configuration that is being used with this task.
*/
- Configuration setAppTask(IBinder token, int taskId, in Rect taskBounds);
+ void setAppTask(IBinder token, int taskId, in Rect taskBounds, in Configuration config);
void setAppOrientation(IApplicationToken token, int requestedOrientation);
int getAppOrientation(IApplicationToken token);
void setFocusedApp(IBinder token, boolean moveFocusNow);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 16d9bf3..665069c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3823,6 +3823,12 @@
private static SparseArray<String> mAttributeMap;
/**
+ * Queue of pending runnables. Used to postpone calls to post() until this
+ * view is attached and has a handler.
+ */
+ private HandlerActionQueue mRunQueue;
+
+ /**
* @hide
*/
String mStartActivityRequestWho;
@@ -13010,6 +13016,18 @@
}
/**
+ * Returns the queue of runnable for this view.
+ *
+ * @return the queue of runnables for this view
+ */
+ private HandlerActionQueue getRunQueue() {
+ if (mRunQueue == null) {
+ mRunQueue = new HandlerActionQueue();
+ }
+ return mRunQueue;
+ }
+
+ /**
* Gets the view root associated with the View.
* @return The view root, or null if none.
* @hide
@@ -13046,8 +13064,10 @@
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
- // Assume that post will succeed later
- ViewRootImpl.getRunQueue().post(action);
+
+ // Postpone the runnable until we know on which thread it needs to run.
+ // Assume that the runnable will be successfully placed after attach.
+ getRunQueue().post(action);
return true;
}
@@ -13075,8 +13095,10 @@
if (attachInfo != null) {
return attachInfo.mHandler.postDelayed(action, delayMillis);
}
- // Assume that post will succeed later
- ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
+
+ // Postpone the runnable until we know on which thread it needs to run.
+ // Assume that the runnable will be successfully placed after attach.
+ getRunQueue().postDelayed(action, delayMillis);
return true;
}
@@ -13095,8 +13117,9 @@
attachInfo.mViewRootImpl.mChoreographer.postCallback(
Choreographer.CALLBACK_ANIMATION, action, null);
} else {
- // Assume that post will succeed later
- ViewRootImpl.getRunQueue().post(action);
+ // Postpone the runnable until we know
+ // on which thread it needs to run.
+ getRunQueue().post(action);
}
}
@@ -13118,8 +13141,9 @@
attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed(
Choreographer.CALLBACK_ANIMATION, action, null, delayMillis);
} else {
- // Assume that post will succeed later
- ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
+ // Postpone the runnable until we know
+ // on which thread it needs to run.
+ getRunQueue().postDelayed(action, delayMillis);
}
}
@@ -13146,8 +13170,7 @@
attachInfo.mViewRootImpl.mChoreographer.removeCallbacks(
Choreographer.CALLBACK_ANIMATION, action, null);
}
- // Assume that post will succeed later
- ViewRootImpl.getRunQueue().removeCallbacks(action);
+ getRunQueue().removeCallbacks(action);
}
return true;
}
@@ -14565,7 +14588,6 @@
* this view
*/
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
- //System.out.println("Attached! " + this);
mAttachInfo = info;
if (mOverlay != null) {
mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility);
@@ -14581,6 +14603,11 @@
mAttachInfo.mScrollContainers.add(this);
mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED;
}
+ // Transfer all pending runnables.
+ if (mRunQueue != null) {
+ mRunQueue.executeActions(info.mHandler);
+ mRunQueue = null;
+ }
performCollectViewAttributes(mAttachInfo, visibility);
onAttachedToWindow();
@@ -16866,7 +16893,9 @@
Choreographer.CALLBACK_ANIMATION, what, who,
Choreographer.subtractFrameDelay(delay));
} else {
- ViewRootImpl.getRunQueue().postDelayed(what, delay);
+ // Postpone the runnable until we know
+ // on which thread it needs to run.
+ getRunQueue().postDelayed(what, delay);
}
}
}
@@ -16884,7 +16913,7 @@
mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks(
Choreographer.CALLBACK_ANIMATION, what, who);
}
- ViewRootImpl.getRunQueue().removeCallbacks(what);
+ getRunQueue().removeCallbacks(what);
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8bbaf36..d26e914 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -28,7 +28,6 @@
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Matrix;
-import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PointF;
@@ -131,7 +130,7 @@
*/
static final int MAX_TRACKBALL_DELAY = 250;
- static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
+ static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
static boolean sFirstDrawComplete = false;
@@ -6759,90 +6758,17 @@
}
}
- static RunQueue getRunQueue() {
- RunQueue rq = sRunQueues.get();
+ static HandlerActionQueue getRunQueue() {
+ HandlerActionQueue rq = sRunQueues.get();
if (rq != null) {
return rq;
}
- rq = new RunQueue();
+ rq = new HandlerActionQueue();
sRunQueues.set(rq);
return rq;
}
/**
- * The run queue is used to enqueue pending work from Views when no Handler is
- * attached. The work is executed during the next call to performTraversals on
- * the thread.
- * @hide
- */
- static final class RunQueue {
- private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
-
- void post(Runnable action) {
- postDelayed(action, 0);
- }
-
- void postDelayed(Runnable action, long delayMillis) {
- HandlerAction handlerAction = new HandlerAction();
- handlerAction.action = action;
- handlerAction.delay = delayMillis;
-
- synchronized (mActions) {
- mActions.add(handlerAction);
- }
- }
-
- void removeCallbacks(Runnable action) {
- final HandlerAction handlerAction = new HandlerAction();
- handlerAction.action = action;
-
- synchronized (mActions) {
- final ArrayList<HandlerAction> actions = mActions;
-
- while (actions.remove(handlerAction)) {
- // Keep going
- }
- }
- }
-
- void executeActions(Handler handler) {
- synchronized (mActions) {
- final ArrayList<HandlerAction> actions = mActions;
- final int count = actions.size();
-
- for (int i = 0; i < count; i++) {
- final HandlerAction handlerAction = actions.get(i);
- handler.postDelayed(handlerAction.action, handlerAction.delay);
- }
-
- actions.clear();
- }
- }
-
- private static class HandlerAction {
- Runnable action;
- long delay;
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- HandlerAction that = (HandlerAction) o;
- return !(action != null ? !action.equals(that.action) : that.action != null);
-
- }
-
- @Override
- public int hashCode() {
- int result = action != null ? action.hashCode() : 0;
- result = 31 * result + (int) (delay ^ (delay >>> 32));
- return result;
- }
- }
- }
-
- /**
* Class for managing the accessibility interaction connection
* based on the global accessibility state.
*/
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index f178c8c..4f4d3e0 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -338,7 +338,7 @@
}
if (mCpuPowerCalculator == null) {
- mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile);
+ mCpuPowerCalculator = new CpuPowerCalculator();
}
mCpuPowerCalculator.reset();
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index a3ef612..d62f7a6 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -23,54 +23,14 @@
private static final String TAG = "CpuPowerCalculator";
private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
- private final double[] mPowerCpuNormal;
-
- /**
- * Reusable array for calculations.
- */
- private final long[] mSpeedStepTimes;
-
- public CpuPowerCalculator(PowerProfile profile) {
- final int speedSteps = profile.getNumSpeedSteps();
- mPowerCpuNormal = new double[speedSteps];
- mSpeedStepTimes = new long[speedSteps];
- for (int p = 0; p < speedSteps; p++) {
- mPowerCpuNormal[p] = profile.getAveragePower(PowerProfile.POWER_CPU_ACTIVE, p);
- }
- }
-
@Override
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
- final int speedSteps = mSpeedStepTimes.length;
-
- long totalTimeAtSpeeds = 0;
- for (int step = 0; step < speedSteps; step++) {
- mSpeedStepTimes[step] = u.getTimeAtCpuSpeed(step, statsType);
- totalTimeAtSpeeds += mSpeedStepTimes[step];
- }
- totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1);
-
app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000;
- if (DEBUG && app.cpuTimeMs != 0) {
- Log.d(TAG, "UID " + u.getUid() + ": CPU time " + app.cpuTimeMs + " ms");
- }
-
- double cpuPowerMaMs = 0;
- for (int step = 0; step < speedSteps; step++) {
- final double ratio = (double) mSpeedStepTimes[step] / totalTimeAtSpeeds;
- final double cpuSpeedStepPower = ratio * app.cpuTimeMs * mPowerCpuNormal[step];
- if (DEBUG && ratio != 0) {
- Log.d(TAG, "UID " + u.getUid() + ": CPU step #"
- + step + " ratio=" + BatteryStatsHelper.makemAh(ratio) + " power="
- + BatteryStatsHelper.makemAh(cpuSpeedStepPower / (60 * 60 * 1000)));
- }
- cpuPowerMaMs += cpuSpeedStepPower;
- }
-
- if (DEBUG && cpuPowerMaMs != 0) {
- Log.d(TAG, "UID " + u.getUid() + ": cpu total power="
- + BatteryStatsHelper.makemAh(cpuPowerMaMs / (60 * 60 * 1000)));
+ app.cpuPowerMah = (double) u.getCpuPowerMaUs(statsType) / (60.0 * 60.0 * 1000.0 * 1000.0);
+ if (DEBUG && (app.cpuTimeMs != 0 || app.cpuPowerMah != 0)) {
+ Log.d(TAG, "UID " + u.getUid() + ": CPU time=" + app.cpuTimeMs + " ms power="
+ + BatteryStatsHelper.makemAh(app.cpuPowerMah));
}
// Keep track of the package with highest drain.
@@ -108,8 +68,5 @@
// Statistics may not have been gathered yet.
app.cpuTimeMs = app.cpuFgTimeMs;
}
-
- // Convert the CPU power to mAh
- app.cpuPowerMah = cpuPowerMaMs / (60 * 60 * 1000);
}
}
diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
index 35eeca7..582c4f1 100644
--- a/core/java/com/android/internal/widget/AbsActionBarView.java
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -19,6 +19,7 @@
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
+import android.view.MotionEvent;
import android.widget.ActionMenuPresenter;
import android.widget.ActionMenuView;
@@ -53,6 +54,9 @@
protected Animator mVisibilityAnim;
+ private boolean mEatingTouch;
+ private boolean mEatingHover;
+
public AbsActionBarView(Context context) {
this(context, null);
}
@@ -97,6 +101,57 @@
}
}
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ // ActionBarViews always eat touch events, but should still respect the touch event dispatch
+ // contract. If the normal View implementation doesn't want the events, we'll just silently
+ // eat the rest of the gesture without reporting the events to the default implementation
+ // since that's what it expects.
+
+ final int action = ev.getActionMasked();
+ if (action == MotionEvent.ACTION_DOWN) {
+ mEatingTouch = false;
+ }
+
+ if (!mEatingTouch) {
+ final boolean handled = super.onTouchEvent(ev);
+ if (action == MotionEvent.ACTION_DOWN && !handled) {
+ mEatingTouch = true;
+ }
+ }
+
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ mEatingTouch = false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onHoverEvent(MotionEvent ev) {
+ // Same deal as onTouchEvent() above. Eat all hover events, but still
+ // respect the touch event dispatch contract.
+
+ final int action = ev.getActionMasked();
+ if (action == MotionEvent.ACTION_HOVER_ENTER) {
+ mEatingHover = false;
+ }
+
+ if (!mEatingHover) {
+ final boolean handled = super.onHoverEvent(ev);
+ if (action == MotionEvent.ACTION_HOVER_ENTER && !handled) {
+ mEatingHover = true;
+ }
+ }
+
+ if (action == MotionEvent.ACTION_HOVER_EXIT
+ || action == MotionEvent.ACTION_CANCEL) {
+ mEatingHover = false;
+ }
+
+ return true;
+ }
+
/**
* Sets whether the bar should be split right now, no questions asked.
* @param split true if the bar should split
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 073a2ad..051845f 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1178,7 +1178,7 @@
* @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
*/
public void requireCredentialEntry(int userId) {
- requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
+ requireStrongAuth(StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
}
/**
@@ -1260,7 +1260,7 @@
value = { STRONG_AUTH_NOT_REQUIRED,
STRONG_AUTH_REQUIRED_AFTER_BOOT,
STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
- SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
+ STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST})
@Retention(RetentionPolicy.SOURCE)
public @interface StrongAuthFlags {}
@@ -1275,14 +1275,14 @@
public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
/**
- * Strong authentication is required because a device admin has requested it.
+ * Strong authentication is required because a device admin has temporarily requested it.
*/
public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
/**
- * Some authentication is required because the user has temporarily disabled trust.
+ * Strong authentication is required because the user has temporarily requested it.
*/
- public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
+ public static final int STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
/**
* Strong authentication is required because the user has been locked out after too many
@@ -1291,7 +1291,6 @@
public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
public static final int DEFAULT = STRONG_AUTH_REQUIRED_AFTER_BOOT;
- private static final int ALLOWING_FINGERPRINT = SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
@@ -1333,7 +1332,7 @@
* current strong authentication requirements.
*/
public boolean isFingerprintAllowedForUser(int userId) {
- return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
+ return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
}
/**
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 414cbb4..aef70be 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -83,6 +83,14 @@
pid_t pid;
int status;
+ // It's necessary to save and restore the errno during this function.
+ // Since errno is stored per thread, changing it here modifies the errno
+ // on the thread on which this signal handler executes. If a signal occurs
+ // between a call and an errno check, it's possible to get the errno set
+ // here.
+ // See b/23572286 for extra information.
+ int saved_errno = errno;
+
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
// Log process-death status that we care about. In general it is
// not safe to call LOG(...) from a signal handler because of
@@ -118,6 +126,8 @@
if (pid < 0 && errno != ECHILD) {
ALOGW("Zygote SIGCHLD error in waitpid: %s", strerror(errno));
}
+
+ errno = saved_errno;
}
// Configures the SIGCHLD handler for the zygote process. This is configured
diff --git a/core/tests/coretests/src/android/view/HandlerActionQueueTest.java b/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
new file mode 100644
index 0000000..fd8f23a
--- /dev/null
+++ b/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class HandlerActionQueueTest extends AndroidTestCase {
+
+ @SmallTest
+ public void testPostAndRemove() {
+ HandlerActionQueue runQueue = new HandlerActionQueue();
+ MockRunnable runnable1 = new MockRunnable();
+ MockRunnable runnable2 = new MockRunnable();
+ MockRunnable runnable3 = new MockRunnable();
+
+ runQueue.post(runnable1);
+ runQueue.post(runnable1);
+ runQueue.post(runnable2);
+ runQueue.postDelayed(runnable1, 100);
+ runQueue.postDelayed(null, 500);
+ assertEquals(5, runQueue.size());
+ assertEquals(0, runQueue.getDelay(0));
+ assertEquals(0, runQueue.getDelay(1));
+ assertEquals(0, runQueue.getDelay(2));
+ assertEquals(100, runQueue.getDelay(3));
+ assertEquals(500, runQueue.getDelay(4));
+ assertEquals(500, runQueue.getDelay(4));
+ assertEquals(runnable1, runQueue.getRunnable(0));
+ assertEquals(runnable1, runQueue.getRunnable(1));
+ assertEquals(runnable2, runQueue.getRunnable(2));
+ assertEquals(runnable1, runQueue.getRunnable(3));
+ assertEquals(null, runQueue.getRunnable(4));
+
+ runQueue.removeCallbacks(runnable1);
+ assertEquals(2, runQueue.size());
+ assertEquals(0, runQueue.getDelay(0));
+ assertEquals(500, runQueue.getDelay(1));
+ assertEquals(runnable2, runQueue.getRunnable(0));
+ assertEquals(null, runQueue.getRunnable(1));
+
+ try {
+ assertNull(runQueue.getRunnable(2));
+ assertFalse(true);
+ } catch (IndexOutOfBoundsException e) {
+ // Should throw an exception.
+ }
+
+ runQueue.removeCallbacks(runnable3);
+ assertEquals(2, runQueue.size());
+
+ runQueue.removeCallbacks(runnable2);
+ assertEquals(1, runQueue.size());
+ assertEquals(null, runQueue.getRunnable(0));
+
+ runQueue.removeCallbacks(null);
+ assertEquals(0, runQueue.size());
+ }
+
+ private static class MockRunnable implements Runnable {
+ @Override
+ public void run() {
+
+ }
+ }
+}
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index 2f28700..f682fb8 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -40,10 +40,9 @@
# For the host
# =====================================================
include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE:= libandroidfw
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
LOCAL_SRC_FILES:= $(hostSources)
@@ -56,13 +55,10 @@
# =====================================================
include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE:= libandroidfw
-LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES:= $(deviceSources)
LOCAL_C_INCLUDES := \
- external/zlib \
system/core/include
LOCAL_STATIC_LIBRARIES := libziparchive libbase
LOCAL_SHARED_LIBRARIES := \
diff --git a/media/java/android/mtp/MtpObjectInfo.java b/media/java/android/mtp/MtpObjectInfo.java
index a080c73..64aa997 100644
--- a/media/java/android/mtp/MtpObjectInfo.java
+++ b/media/java/android/mtp/MtpObjectInfo.java
@@ -294,6 +294,11 @@
mObjectInfo.mThumbPixWidth = objectInfo.mThumbPixWidth;
}
+ public Builder setObjectHandle(int value) {
+ mObjectInfo.mHandle = value;
+ return this;
+ }
+
public Builder setAssociationDesc(int value) {
mObjectInfo.mAssociationDesc = value;
return this;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
index 8b92331..f8ec8f1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -56,6 +56,7 @@
public class CopyService extends IntentService {
public static final String TAG = "CopyService";
+ public static final boolean DEBUG = false;
private static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL";
public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
@@ -159,6 +160,7 @@
// Catch-all to prevent any copy errors from wedging the app.
Log.e(TAG, "Exceptions occurred during copying", e);
} finally {
+ if (DEBUG) Log.d(TAG, "Cleaning up after copy");
ContentProviderClient.releaseQuietly(mSrcClient);
ContentProviderClient.releaseQuietly(mDstClient);
@@ -166,10 +168,12 @@
mNotificationManager.cancel(mJobId, 0);
if (mFailedFiles.size() > 0) {
+ Log.e(TAG, mFailedFiles.size() + " files failed to copy");
final Context context = getApplicationContext();
final Intent navigateIntent = new Intent(context, FilesActivity.class);
navigateIntent.putExtra(EXTRA_STACK, (Parcelable) stack);
navigateIntent.putExtra(EXTRA_FAILURE, FAILURE_COPY);
+ navigateIntent.putExtra(EXTRA_TRANSFER_MODE, transferMode);
navigateIntent.putParcelableArrayListExtra(EXTRA_SRC_LIST, mFailedFiles);
final int titleResourceId = (transferMode == TRANSFER_MODE_COPY ?
@@ -186,6 +190,7 @@
.setAutoCancel(true);
mNotificationManager.notify(mJobId, 0, errorBuilder.build());
}
+ if (DEBUG) Log.d(TAG, "Done cleaning up");
}
}
@@ -398,6 +403,9 @@
*/
private void copy(DocumentInfo srcInfo, DocumentInfo dstDirInfo, int mode)
throws RemoteException {
+ if (DEBUG) Log.d(TAG, "Copying " + srcInfo.displayName + " (" + srcInfo.derivedUri + ")" +
+ " to " + dstDirInfo.displayName + " (" + dstDirInfo.derivedUri + ")");
+
final Uri dstUri = DocumentsContract.createDocument(mDstClient, dstDirInfo.derivedUri,
srcInfo.mimeType, srcInfo.displayName);
if (dstUri == null) {
@@ -499,10 +507,28 @@
srcFile.checkError();
} catch (IOException e) {
copyError = e;
+
try {
- dstFile.closeWithError(copyError.getMessage());
- } catch (IOException closeError) {
- Log.e(TAG, "Error closing destination", closeError);
+ DocumentInfo info = DocumentInfo.fromUri(getContentResolver(), srcUri);
+ mFailedFiles.add(info);
+ Log.e(TAG, "Error while copying " + info.displayName + " (" + info.derivedUri + ")",
+ copyError);
+ } catch (FileNotFoundException ignore) {
+ // Generate a dummy DocumentInfo so an error still gets reflected in the UI for this
+ // file.
+ DocumentInfo info = new DocumentInfo();
+ info.derivedUri = srcUri;
+ info.displayName = "Unknown [" + srcUri + "]";
+ mFailedFiles.add(info);
+ Log.e(TAG, "Error while copying " + srcUri, copyError);
+ }
+
+ if (dstFile != null) {
+ try {
+ dstFile.closeWithError(copyError.getMessage());
+ } catch (IOException closeError) {
+ Log.e(TAG, "Error closing destination", closeError);
+ }
}
} finally {
// This also ensures the file descriptors are closed.
@@ -510,16 +536,6 @@
IoUtils.closeQuietly(dst);
}
- if (copyError != null) {
- // Log errors.
- Log.e(TAG, "Error while copying " + srcUri.toString(), copyError);
- try {
- mFailedFiles.add(DocumentInfo.fromUri(getContentResolver(), srcUri));
- } catch (FileNotFoundException ignore) {
- Log.w(TAG, "Source file gone: " + srcUri, copyError);
- // The source file is gone.
- }
- }
if (copyError != null || mIsCancelled) {
// Clean up half-copied files.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index e15e6e0..ecf03f5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -573,6 +573,9 @@
}
mRecView.setLayoutManager(layout);
+ // TODO: Once b/23691541 is resolved, use a listener within MultiSelectManager instead of
+ // imperatively calling this function.
+ mModel.mSelectionManager.handleLayoutChanged();
// setting layout manager automatically invalidates existing ViewHolders.
mThumbSize = new Point(thumbSize, thumbSize);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
index c27cad3..4284f6f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
@@ -250,6 +250,10 @@
notifySelectionChanged();
}
+ public void handleLayoutChanged() {
+ mBandSelectManager.handleLayoutChanged();
+ }
+
/**
* Clears the selection, without notifying anyone.
*/
@@ -1192,6 +1196,18 @@
}
/**
+ * Handle a change in layout by cleaning up and getting rid of the old model and creating
+ * a new model which will track the new layout.
+ */
+ public void handleLayoutChanged() {
+ mModel.removeOnSelectionChangedListener(this);
+ mModel.stopListening();
+
+ mModel = new BandSelectModel((RuntimeRecyclerViewHelper) mHelper);
+ mModel.addOnSelectionChangedListener(this);
+ }
+
+ /**
* Processes a MotionEvent by starting, ending, or resizing the band select overlay.
* @param e
*/
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index fc6117f..cfc232c 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -29,6 +29,7 @@
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.graphics.Bitmap;
+import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
@@ -472,6 +473,10 @@
}
}
+ private void handleFingerprintLockoutReset() {
+ updateFingerprintListeningState();
+ }
+
private void setFingerprintRunningState(int fingerprintRunningState) {
boolean wasRunning = mFingerprintRunningState == FINGERPRINT_STATE_RUNNING;
boolean isRunning = fingerprintRunningState == FINGERPRINT_STATE_RUNNING;
@@ -681,6 +686,14 @@
}
};
+ private final FingerprintManager.LockoutResetCallback mLockoutResetCallback
+ = new FingerprintManager.LockoutResetCallback() {
+ @Override
+ public void onLockoutReset() {
+ handleFingerprintLockoutReset();
+ }
+ };
+
private FingerprintManager.AuthenticationCallback mAuthenticationCallback
= new AuthenticationCallback() {
@@ -1003,6 +1016,9 @@
mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
updateFingerprintListeningState();
+ if (mFpm != null) {
+ mFpm.addLockoutResetCallback(mLockoutResetCallback);
+ }
}
private void updateFingerprintListeningState() {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java b/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
new file mode 100644
index 0000000..48d5dcf
--- /dev/null
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2015 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.mtp;
+
+import android.database.MatrixCursor;
+import android.mtp.MtpObjectInfo;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+
+import java.util.Date;
+
+final class CursorHelper {
+ static final int DUMMY_HANDLE_FOR_ROOT = 0;
+
+ private CursorHelper() {
+ }
+
+ static void addToCursor(MtpRoot root, MatrixCursor.RowBuilder builder) {
+ final Identifier identifier = new Identifier(
+ root.mDeviceId, root.mStorageId, DUMMY_HANDLE_FOR_ROOT);
+ builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
+ builder.add(Document.COLUMN_DISPLAY_NAME, root.mDescription);
+ builder.add(Document.COLUMN_MIME_TYPE, DocumentsContract.Document.MIME_TYPE_DIR);
+ builder.add(Document.COLUMN_LAST_MODIFIED, null);
+ builder.add(Document.COLUMN_FLAGS, 0);
+ builder.add(Document.COLUMN_SIZE,
+ (int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE));
+ }
+
+ static void addToCursor(MtpObjectInfo objectInfo, Identifier rootIdentifier,
+ MatrixCursor.RowBuilder builder) {
+ final Identifier identifier = new Identifier(
+ rootIdentifier.mDeviceId, rootIdentifier.mStorageId, objectInfo.getObjectHandle());
+ final String mimeType = formatTypeToMimeType(objectInfo.getFormat());
+
+ int flag = 0;
+ if (objectInfo.getProtectionStatus() == 0) {
+ flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
+ DocumentsContract.Document.FLAG_SUPPORTS_WRITE;
+ if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR) {
+ flag |= DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE;
+ }
+ }
+ if (objectInfo.getThumbCompressedSize() > 0) {
+ flag |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
+ }
+
+ builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
+ builder.add(Document.COLUMN_DISPLAY_NAME, objectInfo.getName());
+ builder.add(Document.COLUMN_MIME_TYPE, mimeType);
+ builder.add(
+ Document.COLUMN_LAST_MODIFIED,
+ objectInfo.getDateModified() != 0 ? objectInfo.getDateModified() : null);
+ builder.add(Document.COLUMN_FLAGS, flag);
+ builder.add(Document.COLUMN_SIZE, objectInfo.getCompressedSize());
+ }
+
+ static String formatTypeToMimeType(int format) {
+ // TODO: Add complete list of mime types.
+ switch (format) {
+ case 0x3001:
+ return DocumentsContract.Document.MIME_TYPE_DIR;
+ case 0x3009:
+ return "audio/mp3";
+ case 0x3801:
+ return "image/jpeg";
+ default:
+ return "application/octet-stream";
+ }
+ }
+
+ static int mimeTypeToFormatType(String mimeType) {
+ // TODO: Add complete list of mime types.
+ switch (mimeType.toLowerCase()) {
+ case Document.MIME_TYPE_DIR:
+ return 0x3001;
+ case "audio/mp3":
+ return 0x3009;
+ case "image/jpeg":
+ return 0x3801;
+ default:
+ return 0x3000; // Undefined object.
+ }
+ }
+}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
index c430def..d4c4331 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
@@ -19,6 +19,7 @@
import android.content.ContentResolver;
import android.database.Cursor;
import android.database.MatrixCursor;
+import android.mtp.MtpObjectInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Process;
@@ -34,6 +35,7 @@
* Loader for MTP document.
* At the first request, the loader returns only first NUM_INITIAL_ENTRIES. Then it launches
* background thread to load the rest documents and caches its result for next requests.
+ * TODO: Rename this class to ObjectInfoLoader
*/
class DocumentLoader {
static final int NUM_INITIAL_ENTRIES = 10;
@@ -50,13 +52,13 @@
mResolver = resolver;
}
- private static MtpDocument[] loadDocuments(MtpManager manager, int deviceId, int[] handles)
+ private static MtpObjectInfo[] loadDocuments(MtpManager manager, int deviceId, int[] handles)
throws IOException {
- final MtpDocument[] documents = new MtpDocument[handles.length];
+ final MtpObjectInfo[] objectInfos = new MtpObjectInfo[handles.length];
for (int i = 0; i < handles.length; i++) {
- documents[i] = manager.getDocument(deviceId, handles[i]);
+ objectInfos[i] = manager.getObjectInfo(deviceId, handles[i]);
}
- return documents;
+ return objectInfos;
}
synchronized Cursor queryChildDocuments(String[] columnNames, Identifier parent)
@@ -66,7 +68,7 @@
int parentHandle = parent.mObjectHandle;
// Need to pass the special value MtpManager.OBJECT_HANDLE_ROOT_CHILDREN to
// getObjectHandles if we would like to obtain children under the root.
- if (parentHandle == MtpDocument.DUMMY_HANDLE_FOR_ROOT) {
+ if (parentHandle == CursorHelper.DUMMY_HANDLE_FOR_ROOT) {
parentHandle = MtpManager.OBJECT_HANDLE_ROOT_CHILDREN;
}
task = new LoaderTask(parent, mMtpManager.getObjectHandles(
@@ -89,14 +91,18 @@
return task.createCursor(mResolver, columnNames);
}
- synchronized void clearCache(int deviceId) {
+ synchronized void clearTasks(int deviceId) {
mTaskList.clearTaskForDevice(deviceId);
}
- synchronized void clearCache() {
+ synchronized void clearCompletedTasks() {
mTaskList.clearCompletedTask();
}
+ synchronized void clearTask(Identifier parentIdentifier) {
+ mTaskList.clearTask(parentIdentifier);
+ }
+
private class BackgroundLoaderThread extends Thread {
@Override
public void run() {
@@ -114,16 +120,16 @@
deviceId = task.mIdentifier.mDeviceId;
handles = task.getUnloadedObjectHandles(NUM_LOADING_ENTRIES);
}
- MtpDocument[] documents;
+ MtpObjectInfo[] objectInfos;
try {
- documents = loadDocuments(mMtpManager, deviceId, handles);
+ objectInfos = loadDocuments(mMtpManager, deviceId, handles);
} catch (IOException exception) {
- documents = null;
+ objectInfos = null;
Log.d(MtpDocumentsProvider.TAG, exception.getMessage());
}
synchronized (DocumentLoader.this) {
- if (documents != null) {
- task.fillDocuments(documents);
+ if (objectInfos != null) {
+ task.fillDocuments(objectInfos);
final boolean shouldNotify =
task.mLastNotified.getTime() <
new Date().getTime() - NOTIFY_PERIOD_MS ||
@@ -177,19 +183,30 @@
}
}
}
+
+ void clearTask(Identifier parentIdentifier) {
+ for (int i = 0; i < size(); i++) {
+ final LoaderTask task = get(i);
+ if (task.mIdentifier.mDeviceId == parentIdentifier.mDeviceId &&
+ task.mIdentifier.mObjectHandle == parentIdentifier.mObjectHandle) {
+ remove(i);
+ return;
+ }
+ }
+ }
}
private static class LoaderTask {
final Identifier mIdentifier;
final int[] mObjectHandles;
- final MtpDocument[] mDocuments;
+ final MtpObjectInfo[] mObjectInfos;
Date mLastNotified;
int mNumLoaded;
LoaderTask(Identifier identifier, int[] objectHandles) {
mIdentifier = identifier;
mObjectHandles = objectHandles;
- mDocuments = new MtpDocument[mObjectHandles.length];
+ mObjectInfos = new MtpObjectInfo[mObjectHandles.length];
mNumLoaded = 0;
mLastNotified = new Date();
}
@@ -199,7 +216,7 @@
final Identifier rootIdentifier = new Identifier(
mIdentifier.mDeviceId, mIdentifier.mStorageId);
for (int i = 0; i < mNumLoaded; i++) {
- mDocuments[i].addToCursor(rootIdentifier, cursor.newRow());
+ CursorHelper.addToCursor(mObjectInfos[i], rootIdentifier, cursor.newRow());
}
final Bundle extras = new Bundle();
extras.putBoolean(DocumentsContract.EXTRA_LOADING, !completed());
@@ -209,7 +226,7 @@
}
boolean completed() {
- return mNumLoaded == mDocuments.length;
+ return mNumLoaded == mObjectInfos.length;
}
int[] getUnloadedObjectHandles(int count) {
@@ -224,9 +241,9 @@
mLastNotified = new Date();
}
- void fillDocuments(MtpDocument[] documents) {
- for (int i = 0; i < documents.length; i++) {
- mDocuments[mNumLoaded++] = documents[i];
+ void fillDocuments(MtpObjectInfo[] objectInfos) {
+ for (int i = 0; i < objectInfos.length; i++) {
+ mObjectInfos[mNumLoaded++] = objectInfos[i];
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java b/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java
index bd0c837..ae29f52 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java
@@ -41,7 +41,7 @@
Identifier(int deviceId, int storageId) {
- this(deviceId, storageId, MtpDocument.DUMMY_HANDLE_FOR_ROOT);
+ this(deviceId, storageId, CursorHelper.DUMMY_HANDLE_FOR_ROOT);
}
Identifier(int deviceId, int storageId, int objectHandle) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
deleted file mode 100644
index c1d9609..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2015 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.mtp;
-
-import android.database.MatrixCursor;
-import android.mtp.MtpObjectInfo;
-import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.Document;
-
-import java.util.Date;
-
-class MtpDocument {
- static final int DUMMY_HANDLE_FOR_ROOT = 0;
-
- private final int mObjectHandle;
- private final int mFormat;
- private final String mName;
- private final Date mDateModified;
- private final int mSize;
- private final int mThumbSize;
- private final boolean mReadOnly;
-
- /**
- * Constructor for root document.
- */
- MtpDocument(MtpRoot root) {
- this(DUMMY_HANDLE_FOR_ROOT,
- 0x3001, // Directory.
- root.mDescription,
- null, // Unknown name.
- (int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE),
- 0, // Total size.
- true); // Writable.
- }
-
- MtpDocument(MtpObjectInfo objectInfo) {
- this(objectInfo.getObjectHandle(),
- objectInfo.getFormat(),
- objectInfo.getName(),
- objectInfo.getDateModified() != 0 ? new Date(objectInfo.getDateModified()) : null,
- objectInfo.getCompressedSize(),
- objectInfo.getThumbCompressedSize(),
- objectInfo.getProtectionStatus() != 0);
- }
-
- MtpDocument(int objectHandle,
- int format,
- String name,
- Date dateModified,
- int size,
- int thumbSize,
- boolean readOnly) {
- this.mObjectHandle = objectHandle;
- this.mFormat = format;
- this.mName = name;
- this.mDateModified = dateModified;
- this.mSize = size;
- this.mThumbSize = thumbSize;
- this.mReadOnly = readOnly;
- }
-
- void addToCursor(Identifier rootIdentifier, MatrixCursor.RowBuilder builder) {
- final Identifier identifier = new Identifier(
- rootIdentifier.mDeviceId, rootIdentifier.mStorageId, mObjectHandle);
- final String mimeType = formatTypeToMimeType(mFormat);
-
- int flag = 0;
- if (mObjectHandle != DUMMY_HANDLE_FOR_ROOT) {
- if (mThumbSize > 0) {
- flag |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
- }
- if (!mReadOnly) {
- flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
- DocumentsContract.Document.FLAG_SUPPORTS_WRITE;
- }
- }
- if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR && !mReadOnly) {
- flag |= DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE;
- }
-
- builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
- builder.add(Document.COLUMN_DISPLAY_NAME, mName);
- builder.add(Document.COLUMN_MIME_TYPE, mimeType);
- builder.add(
- Document.COLUMN_LAST_MODIFIED,
- mDateModified != null ? mDateModified.getTime() : null);
- builder.add(Document.COLUMN_FLAGS, flag);
- builder.add(Document.COLUMN_SIZE, mSize);
- }
-
- static String formatTypeToMimeType(int format) {
- // TODO: Add complete list of mime types.
- switch (format) {
- case 0x3001:
- return DocumentsContract.Document.MIME_TYPE_DIR;
- case 0x3009:
- return "audio/mp3";
- case 0x3801:
- return "image/jpeg";
- default:
- return "application/octet-stream";
- }
- }
-
- static int mimeTypeToFormatType(String mimeType) {
- // TODO: Add complete list of mime types.
- switch (mimeType.toLowerCase()) {
- case Document.MIME_TYPE_DIR:
- return 0x3001;
- case "audio/mp3":
- return 0x3009;
- case "image/jpeg":
- return 0x3801;
- default:
- return 0x3000; // Undefined object.
- }
- }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index a3cf3e2..78ed161 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -21,11 +21,12 @@
import android.database.Cursor;
import android.database.MatrixCursor;
import android.graphics.Point;
+import android.mtp.MtpObjectInfo;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
-import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsContract;
import android.provider.DocumentsProvider;
import android.util.Log;
@@ -116,37 +117,37 @@
}
final Identifier identifier = Identifier.createFromDocumentId(documentId);
- MtpDocument document = null;
- if (identifier.mObjectHandle != MtpDocument.DUMMY_HANDLE_FOR_ROOT) {
+ if (identifier.mObjectHandle != CursorHelper.DUMMY_HANDLE_FOR_ROOT) {
+ MtpObjectInfo objectInfo;
try {
- document = mMtpManager.getDocument(identifier.mDeviceId, identifier.mObjectHandle);
+ objectInfo = mMtpManager.getObjectInfo(
+ identifier.mDeviceId, identifier.mObjectHandle);
} catch (IOException e) {
throw new FileNotFoundException(e.getMessage());
}
+ final MatrixCursor cursor = new MatrixCursor(projection);
+ CursorHelper.addToCursor(
+ objectInfo,
+ new Identifier(identifier.mDeviceId, identifier.mStorageId),
+ cursor.newRow());
+ return cursor;
} else {
MtpRoot[] roots;
try {
roots = mMtpManager.getRoots(identifier.mDeviceId);
- if (roots != null) {
- for (final MtpRoot root : roots) {
- if (identifier.mStorageId == root.mStorageId) {
- document = new MtpDocument(root);
- break;
- }
- }
- }
- if (document == null) {
- throw new FileNotFoundException();
- }
} catch (IOException e) {
throw new FileNotFoundException(e.getMessage());
}
+ for (final MtpRoot root : roots) {
+ if (identifier.mStorageId != root.mStorageId)
+ continue;
+ final MatrixCursor cursor = new MatrixCursor(projection);
+ CursorHelper.addToCursor(root, cursor.newRow());
+ return cursor;
+ }
}
- final MatrixCursor cursor = new MatrixCursor(projection);
- document.addToCursor(
- new Identifier(identifier.mDeviceId, identifier.mStorageId), cursor.newRow());
- return cursor;
+ throw new FileNotFoundException();
}
@Override
@@ -173,6 +174,8 @@
case "r":
return mPipeManager.readDocument(mMtpManager, identifier);
case "w":
+ // TODO: Clear the parent document loader task (if exists) and call notify
+ // when writing is completed.
return mPipeManager.writeDocument(getContext(), mMtpManager, identifier);
default:
// TODO: Add support for seekable files.
@@ -207,8 +210,10 @@
final int parentHandle =
mMtpManager.getParent(identifier.mDeviceId, identifier.mObjectHandle);
mMtpManager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle);
- notifyChildDocumentsChange(new Identifier(
- identifier.mDeviceId, identifier.mStorageId, parentHandle).toDocumentId());
+ final Identifier parentIdentifier = new Identifier(
+ identifier.mDeviceId, identifier.mStorageId, parentHandle);
+ mDocumentLoader.clearTask(parentIdentifier);
+ notifyChildDocumentsChange(parentIdentifier.toDocumentId());
} catch (IOException error) {
throw new FileNotFoundException(error.getMessage());
}
@@ -216,7 +221,7 @@
@Override
public void onTrimMemory(int level) {
- mDocumentLoader.clearCache();
+ mDocumentLoader.clearCompletedTasks();
}
@Override
@@ -224,11 +229,19 @@
throws FileNotFoundException {
try {
final Identifier parentId = Identifier.createFromDocumentId(parentDocumentId);
+ final ParcelFileDescriptor pipe[] = ParcelFileDescriptor.createReliablePipe();
+ pipe[0].close(); // 0 bytes for a new document.
final int objectHandle = mMtpManager.createDocument(
- parentId.mDeviceId, parentId.mStorageId, parentId.mObjectHandle, mimeType,
- displayName);
- final String documentId = new Identifier(parentId.mDeviceId, parentId.mStorageId,
+ parentId.mDeviceId,
+ new MtpObjectInfo.Builder()
+ .setStorageId(parentId.mStorageId)
+ .setParent(parentId.mObjectHandle)
+ .setFormat(CursorHelper.mimeTypeToFormatType(mimeType))
+ .setName(displayName)
+ .build(), pipe[1]);
+ final String documentId = new Identifier(parentId.mDeviceId, parentId.mStorageId,
objectHandle).toDocumentId();
+ mDocumentLoader.clearTask(parentId);
notifyChildDocumentsChange(parentDocumentId);
return documentId;
} catch (IOException error) {
@@ -244,7 +257,7 @@
void closeDevice(int deviceId) throws IOException {
mMtpManager.closeDevice(deviceId);
- mDocumentLoader.clearCache(deviceId);
+ mDocumentLoader.clearTasks(deviceId);
mRootScanner.scanNow();
}
@@ -253,7 +266,7 @@
for (int deviceId : mMtpManager.getOpenedDeviceIds()) {
try {
mMtpManager.closeDevice(deviceId);
- mDocumentLoader.clearCache(deviceId);
+ mDocumentLoader.clearTasks(deviceId);
closed = true;
} catch (IOException d) {
Log.d(TAG, "Failed to close the MTP device: " + deviceId);
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 6647009..ca78a3e 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -20,6 +20,7 @@
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
+import android.mtp.MtpConstants;
import android.mtp.MtpDevice;
import android.mtp.MtpObjectInfo;
import android.os.ParcelFileDescriptor;
@@ -108,16 +109,12 @@
return results;
}
- synchronized MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
+ synchronized MtpObjectInfo getObjectInfo(int deviceId, int objectHandle)
+ throws IOException {
final MtpDevice device = getDevice(deviceId);
return device.getObjectInfo(objectHandle);
}
- synchronized MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
- final MtpDevice device = getDevice(deviceId);
- return new MtpDocument(device.getObjectInfo(objectHandle));
- }
-
synchronized int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle)
throws IOException {
final MtpDevice device = getDevice(deviceId);
@@ -142,25 +139,20 @@
}
}
- // TODO: Remove this method.
- synchronized int createDocument(int deviceId, int storageId, int parentObjectHandle,
- String mimeType, String name) throws IOException {
- final MtpObjectInfo objectInfo = new MtpObjectInfo.Builder()
- .setName(name)
- .setStorageId(storageId)
- .setParent(parentObjectHandle)
- .setFormat(MtpDocument.mimeTypeToFormatType(mimeType))
- .build();
- return createDocument(deviceId, objectInfo);
- }
-
- synchronized int createDocument(int deviceId, MtpObjectInfo objectInfo) throws IOException {
+ synchronized int createDocument(int deviceId, MtpObjectInfo objectInfo,
+ ParcelFileDescriptor source) throws IOException {
final MtpDevice device = getDevice(deviceId);
- final MtpObjectInfo result = device.sendObjectInfo(objectInfo);
- if (result == null) {
+ final MtpObjectInfo sendObjectInfoResult = device.sendObjectInfo(objectInfo);
+ if (sendObjectInfoResult == null) {
throw new IOException("Failed to create a document");
}
- return result.getObjectHandle();
+ if (objectInfo.getFormat() != MtpConstants.FORMAT_ASSOCIATION) {
+ if (!device.sendObject(sendObjectInfoResult.getObjectHandle(),
+ sendObjectInfoResult.getCompressedSize(), source)) {
+ throw new IOException("Failed to send contents of a document");
+ }
+ }
+ return sendObjectInfoResult.getObjectHandle();
}
synchronized int getParent(int deviceId, int objectHandle) throws IOException {
@@ -178,13 +170,6 @@
device.importFile(objectHandle, target);
}
- synchronized void sendObject(int deviceId, int objectHandle, int size,
- ParcelFileDescriptor source) throws IOException {
- final MtpDevice device = getDevice(deviceId);
- if (!device.sendObject(objectHandle, size, source))
- throw new IOException("Failed to send a document");
- }
-
private MtpDevice getDevice(int deviceId) throws IOException {
final MtpDevice device = mDevices.get(deviceId);
if (device == null) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
index 53f1b65..cd38f1e 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
@@ -139,20 +139,15 @@
// Delete the target object info if it already exists (as a placeholder).
mManager.deleteDocument(mIdentifier.mDeviceId, mIdentifier.mObjectHandle);
- // Create the target object info with a correct file size.
- final int targetObjectHandle =
- mManager.createDocument(
- mIdentifier.mDeviceId,
- new MtpObjectInfo.Builder(placeholderObjectInfo)
- .setCompressedSize((int) tempFile.length())
- .build());
-
- // Upload the object.
+ // Create the target object info with a correct file size and upload the file.
+ final MtpObjectInfo targetObjectInfo =
+ new MtpObjectInfo.Builder(placeholderObjectInfo)
+ .setCompressedSize((int) tempFile.length())
+ .build();
final ParcelFileDescriptor tempInputDescriptor = ParcelFileDescriptor.open(
tempFile, ParcelFileDescriptor.MODE_READ_ONLY);
- mManager.sendObject(mIdentifier.mDeviceId,
- targetObjectHandle, (int) tempFile.length(), tempInputDescriptor);
-
+ mManager.createDocument(mIdentifier.mDeviceId,
+ targetObjectInfo, tempInputDescriptor);
} catch (IOException error) {
Log.w(MtpDocumentsProvider.TAG,
"Failed to send a file because of: " + error.getMessage());
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
index 1e015bd..a012d7f 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.database.Cursor;
+import android.mtp.MtpObjectInfo;
import android.net.Uri;
import android.provider.DocumentsContract;
import android.test.AndroidTestCase;
@@ -31,14 +32,14 @@
@SmallTest
public class DocumentLoaderTest extends AndroidTestCase {
- private BlockableTestMtpMaanger mManager;
+ private BlockableTestMtpManager mManager;
private TestContentResolver mResolver;
private DocumentLoader mLoader;
final private Identifier mParentIdentifier = new Identifier(0, 0, 0);
@Override
public void setUp() {
- mManager = new BlockableTestMtpMaanger(getContext());
+ mManager = new BlockableTestMtpManager(getContext());
mResolver = new TestContentResolver();
mLoader = new DocumentLoader(mManager, mResolver);
}
@@ -85,22 +86,17 @@
for (int i = 0; i < childDocuments.length; i++) {
final int objectHandle = i + 1;
childDocuments[i] = objectHandle;
- manager.setDocument(0, objectHandle, new MtpDocument(
- objectHandle,
- 0 /* format */,
- "file" + objectHandle,
- new Date(),
- 1024,
- 0 /* thumbnail size */,
- false /* not read only */));
+ manager.setObjectInfo(0, new MtpObjectInfo.Builder()
+ .setObjectHandle(objectHandle)
+ .build());
}
manager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, childDocuments);
}
- private static class BlockableTestMtpMaanger extends TestMtpManager {
+ private static class BlockableTestMtpManager extends TestMtpManager {
final private Map<String, CountDownLatch> blockedDocuments = new HashMap<>();
- BlockableTestMtpMaanger(Context context) {
+ BlockableTestMtpManager(Context context) {
super(context);
}
@@ -113,7 +109,7 @@
}
@Override
- MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
+ MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
final CountDownLatch latch = blockedDocuments.get(pack(deviceId, objectHandle));
if (latch != null) {
try {
@@ -122,7 +118,7 @@
fail();
}
}
- return super.getDocument(deviceId, objectHandle);
+ return super.getObjectInfo(deviceId, objectHandle);
}
}
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 1826bd0..cbb72d1 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -17,9 +17,12 @@
package com.android.mtp;
import android.database.Cursor;
+import android.mtp.MtpConstants;
+import android.mtp.MtpObjectInfo.Builder;
+import android.mtp.MtpObjectInfo;
import android.net.Uri;
-import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsContract;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
@@ -204,14 +207,14 @@
}
public void testQueryDocument() throws IOException {
- mMtpManager.setDocument(0, 2, new MtpDocument(
- 2 /* object handle */,
- 0x3801 /* JPEG */,
- "image.jpg" /* display name */,
- new Date(1422716400000L) /* modified date */,
- 1024 * 1024 * 5 /* file size */,
- 1024 * 50 /* thumbnail size */,
- false /* read only */));
+ mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+ .setObjectHandle(2)
+ .setFormat(0x3801)
+ .setName("image.jpg")
+ .setDateModified(1422716400000L)
+ .setCompressedSize(1024 * 1024 * 5)
+ .setThumbCompressedSize(1024 * 50)
+ .build());
final Cursor cursor = mProvider.queryDocument("0_1_2", null);
assertEquals(1, cursor.getCount());
@@ -229,14 +232,12 @@
}
public void testQueryDocument_directory() throws IOException {
- mMtpManager.setDocument(0, 2, new MtpDocument(
- 2 /* object handle */,
- 0x3001 /* directory */,
- "directory" /* display name */,
- new Date(1422716400000L) /* modified date */,
- 0 /* file size */,
- 0 /* thumbnail size */,
- false /* read only */));
+ mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+ .setObjectHandle(2)
+ .setFormat(0x3001 /* directory format */)
+ .setName("directory")
+ .setDateModified(1422716400000L)
+ .build());
final Cursor cursor = mProvider.queryDocument("0_1_2", null);
assertEquals(1, cursor.getCount());
@@ -278,14 +279,14 @@
public void testQueryChildDocuments() throws Exception {
mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 });
- mMtpManager.setDocument(0, 1, new MtpDocument(
- 1 /* object handle */,
- 0x3801 /* JPEG */,
- "image.jpg" /* display name */,
- new Date(0) /* modified date */,
- 1024 * 1024 * 5 /* file size */,
- 1024 * 50 /* thumbnail size */,
- true /* read only */));
+ mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+ .setObjectHandle(1)
+ .setFormat(0x3801 /* JPEG */)
+ .setName("image.jpg")
+ .setCompressedSize(1024 * 1024 * 5)
+ .setThumbCompressedSize(5 * 1024)
+ .setProtectionStatus(MtpConstants.PROTECTION_STATUS_READ_ONLY)
+ .build());
final Cursor cursor = mProvider.queryChildDocuments("0_0_0", null, null);
assertEquals(1, cursor.getCount());
@@ -321,15 +322,10 @@
}
public void testDeleteDocument() throws FileNotFoundException {
- mMtpManager.setDocument(0, 1, new MtpDocument(
- 1 /* object handle */,
- 0x3801 /* JPEG */,
- "image.jpg" /* display name */,
- new Date(1422716400000L) /* modified date */,
- 1024 * 1024 * 5 /* file size */,
- 1024 * 50 /* thumbnail size */,
- false /* not read only */));
- mMtpManager.setParent(0, 1, 2);
+ mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+ .setObjectHandle(1)
+ .setParent(2)
+ .build());
mProvider.deleteDocument("0_0_1");
assertEquals(1, mResolver.getChangeCount(
DocumentsContract.buildChildDocumentsUri(
@@ -337,7 +333,9 @@
}
public void testDeleteDocument_error() {
- mMtpManager.setParent(0, 1, 2);
+ mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+ .setObjectHandle(2)
+ .build());
try {
mProvider.deleteDocument("0_0_1");
fail();
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
index cfb8b04..53018cc 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
@@ -16,6 +16,7 @@
package com.android.mtp;
+import android.mtp.MtpObjectInfo;
import android.os.ParcelFileDescriptor;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
@@ -56,7 +57,9 @@
public void testWriteDocument_basic() throws Exception {
// Create a placeholder file which should be replaced by a real file later.
- mtpManager.setDocument(0, 1, new MtpDocument(1, 0, "", new Date(), 0, 0, false));
+ mtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+ .setObjectHandle(1)
+ .build());
// Upload testing bytes.
final ParcelFileDescriptor descriptor = mPipeManager.writeDocument(
@@ -69,14 +72,14 @@
// Check if the placeholder file is removed.
try {
- final MtpDocument placeholderDocument = mtpManager.getDocument(0, 1);
+ final MtpObjectInfo placeholderDocument = mtpManager.getObjectInfo(0, 1);
fail(); // The placeholder file has not been deleted.
} catch (IOException e) {
// Expected error, as the file is gone.
}
// Confirm that the target file is created.
- final MtpDocument targetDocument = mtpManager.getDocument(
+ final MtpObjectInfo targetDocument = mtpManager.getObjectInfo(
0, TestMtpManager.CREATED_DOCUMENT_HANDLE);
assertTrue(targetDocument != null);
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
index 94b5ba0..5605388 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
@@ -40,10 +40,9 @@
private final Set<Integer> mValidDevices = new HashSet<>();
private final Set<Integer> mOpenedDevices = new TreeSet<>();
private final Map<Integer, MtpRoot[]> mRoots = new HashMap<>();
- private final Map<String, MtpDocument> mDocuments = new HashMap<>();
+ private final Map<String, MtpObjectInfo> mObjectInfos = new HashMap<>();
private final Map<String, int[]> mObjectHandles = new HashMap<>();
private final Map<String, byte[]> mThumbnailBytes = new HashMap<>();
- private final Map<String, Integer> mParents = new HashMap<>();
private final Map<String, byte[]> mImportFileBytes = new HashMap<>();
TestMtpManager(Context context) {
@@ -54,16 +53,16 @@
mValidDevices.add(deviceId);
}
- void setObjectHandles(int deviceId, int storageId, int objectHandle, int[] documents) {
- mObjectHandles.put(pack(deviceId, storageId, objectHandle), documents);
+ void setObjectHandles(int deviceId, int storageId, int parentHandle, int[] objectHandles) {
+ mObjectHandles.put(pack(deviceId, storageId, parentHandle), objectHandles);
}
void setRoots(int deviceId, MtpRoot[] roots) {
mRoots.put(deviceId, roots);
}
- void setDocument(int deviceId, int objectHandle, MtpDocument document) {
- mDocuments.put(pack(deviceId, objectHandle), document);
+ void setObjectInfo(int deviceId, MtpObjectInfo objectInfo) {
+ mObjectInfos.put(pack(deviceId, objectInfo.getObjectHandle()), objectInfo);
}
void setImportFileBytes(int deviceId, int objectHandle, byte[] bytes) {
@@ -78,10 +77,6 @@
mThumbnailBytes.put(pack(deviceId, objectHandle), bytes);
}
- void setParent(int deviceId, int objectHandle, int parentObjectHandle) {
- mParents.put(pack(deviceId, objectHandle), parentObjectHandle);
- }
-
@Override
void openDevice(int deviceId) throws IOException {
if (!mValidDevices.contains(deviceId) || mOpenedDevices.contains(deviceId)) {
@@ -108,22 +103,13 @@
}
@Override
- MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
- final String key = pack(deviceId, objectHandle);
- if (mDocuments.containsKey(key)) {
- return mDocuments.get(key);
- } else {
- throw new IOException("getDocument error: " + key);
- }
- }
-
- @Override
MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
- final MtpDocument document = getDocument(deviceId, objectHandle);
- // It's impossible to set an object id of MtpObjectInfo at this stage. Also,
- // it's hard to get any information from MtpDocument, as it's designed to return them
- // only via cursors. Rework these.
- return new MtpObjectInfo.Builder().build();
+ final String key = pack(deviceId, objectHandle);
+ if (mObjectInfos.containsKey(key)) {
+ return mObjectInfos.get(key);
+ } else {
+ throw new IOException("getObjectInfo error: " + key);
+ }
}
@Override
@@ -151,44 +137,29 @@
}
@Override
- int createDocument(int deviceId, MtpObjectInfo objectInfo) throws IOException {
- // For simplicity, it allows to create only one document, and it always has the hardcoded
- // CREATED_DOCUMENT_HANDLE document handle.
+ int createDocument(int deviceId, MtpObjectInfo objectInfo, ParcelFileDescriptor source)
+ throws IOException {
final String key = pack(deviceId, CREATED_DOCUMENT_HANDLE);
- if (!mDocuments.containsKey(key)) {
- mDocuments.put(key, new MtpDocument(
- CREATED_DOCUMENT_HANDLE,
- objectInfo.getFormat(),
- objectInfo.getName(),
- new Date(objectInfo.getDateModified()),
- objectInfo.getCompressedSize(),
- objectInfo.getThumbCompressedSize(),
- false /* Always writable for testing. */));
- } else {
+ if (mObjectInfos.containsKey(key)) {
throw new IOException();
}
+ mObjectInfos.put(key, objectInfo);
+ if (objectInfo.getFormat() != 0x3001) {
+ try (final ParcelFileDescriptor.AutoCloseInputStream inputStream =
+ new ParcelFileDescriptor.AutoCloseInputStream(source)) {
+ final byte[] buffer = new byte[objectInfo.getCompressedSize()];
+ if (inputStream.read(buffer, 0, objectInfo.getCompressedSize()) !=
+ objectInfo.getCompressedSize()) {
+ throw new IOException();
+ }
+
+ mImportFileBytes.put(pack(deviceId, CREATED_DOCUMENT_HANDLE), buffer);
+ }
+ }
return CREATED_DOCUMENT_HANDLE;
}
@Override
- void sendObject(int deviceId, int objectHandle, int size, ParcelFileDescriptor source)
- throws IOException {
- final String key = pack(deviceId, objectHandle);
- if (!mDocuments.containsKey(key)) {
- throw new IOException();
- }
-
- ParcelFileDescriptor.AutoCloseInputStream inputStream =
- new ParcelFileDescriptor.AutoCloseInputStream(source);
- byte[] buffer = new byte[size];
- if (inputStream.read(buffer, 0, size) != size) {
- throw new IOException();
- }
-
- mImportFileBytes.put(pack(deviceId, objectHandle), buffer);
- }
-
- @Override
byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
final String key = pack(deviceId, objectHandle);
if (mThumbnailBytes.containsKey(key)) {
@@ -201,18 +172,18 @@
@Override
void deleteDocument(int deviceId, int objectHandle) throws IOException {
final String key = pack(deviceId, objectHandle);
- if (mDocuments.containsKey(key)) {
- mDocuments.remove(key);
+ if (mObjectInfos.containsKey(key)) {
+ mObjectInfos.remove(key);
} else {
throw new IOException();
}
}
@Override
- synchronized int getParent(int deviceId, int objectHandle) throws IOException {
+ int getParent(int deviceId, int objectHandle) throws IOException {
final String key = pack(deviceId, objectHandle);
- if (mParents.containsKey(key)) {
- return mParents.get(key);
+ if (mObjectInfos.containsKey(key)) {
+ return mObjectInfos.get(key).getParent();
} else {
throw new IOException();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index d30411a..f4439bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -262,14 +262,21 @@
return (secure && !canSkipBouncer) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
}
+ /**
+ * Resolves the intent to launch the camera application.
+ */
+ public ResolveInfo resolveCameraIntent() {
+ return mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
+ PackageManager.MATCH_DEFAULT_ONLY,
+ KeyguardUpdateMonitor.getCurrentUser());
+ }
+
private void updateCameraVisibility() {
if (mCameraImageView == null) {
// Things are not set up yet; reply hazy, ask again later
return;
}
- ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
- PackageManager.MATCH_DEFAULT_ONLY,
- KeyguardUpdateMonitor.getCurrentUser());
+ ResolveInfo resolved = resolveCameraIntent();
boolean visible = !isCameraDisabledByDpm() && resolved != null
&& getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance)
&& mUserSetupComplete;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 93ecb06..d0a7f8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -166,10 +166,13 @@
if (mAccessibilityController == null) {
return;
}
+ boolean trustManagedOrFingerprintAllowed = mUnlockMethodCache.isTrustManaged()
+ || KeyguardUpdateMonitor.getInstance(mContext).isUnlockingWithFingerprintAllowed();
+
boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled();
- boolean clickToForceLock = mUnlockMethodCache.isTrustManaged()
+ boolean clickToForceLock = trustManagedOrFingerprintAllowed
&& !mAccessibilityController.isAccessibilityEnabled();
- boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged()
+ boolean longClickToForceLock = trustManagedOrFingerprintAllowed
&& !clickToForceLock;
setClickable(clickToForceLock || clickToUnlock);
setLongClickable(longClickToForceLock);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 3ad7246..814a65e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -21,7 +21,10 @@
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
+import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -62,6 +65,8 @@
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackStateAnimator;
+import java.util.List;
+
public class NotificationPanelView extends PanelView implements
ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
@@ -2462,7 +2467,28 @@
getCenterIcon().setLaunchingAffordance(launchingAffordance);
}
- public boolean canCameraGestureBeLaunched() {
- return !mAfforanceHelper.isSwipingInProgress();
+ /**
+ * Whether the camera application can be launched for the camera launch gesture.
+ *
+ * @param keyguardIsShowing whether keyguard is being shown
+ */
+ public boolean canCameraGestureBeLaunched(boolean keyguardIsShowing) {
+ ResolveInfo resolveInfo = mKeyguardBottomArea.resolveCameraIntent();
+ String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null)
+ ? null : resolveInfo.activityInfo.packageName;
+ return packageToLaunch != null &&
+ (keyguardIsShowing || !isForegroundApp(packageToLaunch)) &&
+ !mAfforanceHelper.isSwipingInProgress();
+ }
+
+ /**
+ * Return true if the applications with the package name is running in foreground.
+ *
+ * @param pkgName application package name.
+ */
+ private boolean isForegroundApp(String pkgName) {
+ ActivityManager am = getContext().getSystemService(ActivityManager.class);
+ List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
+ return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName());
}
}
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 7b04da0..ab1b597 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -4150,7 +4150,8 @@
@Override
public void onCameraLaunchGestureDetected() {
- if (!mNotificationPanel.canCameraGestureBeLaunched()) {
+ if (!mNotificationPanel.canCameraGestureBeLaunched(
+ mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
return;
}
if (!mDeviceInteractive) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 95a8d39..6475cbf 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -421,8 +421,9 @@
}
}
} else {
- final boolean vmute = row.ss.level == 0;
- mController.setStreamVolume(stream, vmute ? row.lastAudibleLevel : 0);
+ final boolean vmute = row.ss.level == row.ss.levelMin;
+ mController.setStreamVolume(stream,
+ vmute ? row.lastAudibleLevel : row.ss.levelMin);
}
row.userAttempt = 0; // reset the grace period, slider should update immediately
}
@@ -1024,6 +1025,7 @@
final int minProgress = mRow.ss.levelMin * 100;
if (progress < minProgress) {
seekBar.setProgress(minProgress);
+ progress = minProgress;
}
}
final int userLevel = getImpliedLevel(seekBar, progress);
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 4288fa2..882899e 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -177,7 +177,7 @@
private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
- private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = 60*1000;
+ private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_MIN_FUTURITY;
private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 15*60*1000;
private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4aef23b..c0ffb56 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17411,8 +17411,10 @@
}
// Can't call out of the system process with a lock held, so post a message.
- mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
- app.instrumentationUiAutomationConnection).sendToTarget();
+ if (app.instrumentationUiAutomationConnection != null) {
+ mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
+ app.instrumentationUiAutomationConnection).sendToTarget();
+ }
app.instrumentationWatcher = null;
app.instrumentationUiAutomationConnection = null;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index f50df3a..37ddd4d 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3975,8 +3975,7 @@
* for whatever reason. Ensures the HistoryRecord is updated with the
* correct configuration and all other bookkeeping is handled.
*/
- final boolean ensureActivityConfigurationLocked(ActivityRecord r,
- int globalChanges) {
+ final boolean ensureActivityConfigurationLocked(ActivityRecord r, int globalChanges) {
if (mConfigWillChange) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Skipping config check (will change): " + r);
@@ -4589,25 +4588,19 @@
void addConfigOverride(ActivityRecord r, TaskRecord task) {
final Rect bounds = task.getLaunchBounds();
- final Configuration config =
- mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
- r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
- (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
- r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
- bounds);
- if (config != null) {
- task.updateOverrideConfiguration(config, bounds);
- }
+ final Configuration config = task.updateOverrideConfiguration(mStackId, bounds);
+ mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
+ r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
+ (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
+ r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
+ bounds, config);
r.taskConfigOverride = task.mOverrideConfig;
}
private void setAppTask(ActivityRecord r, TaskRecord task) {
final Rect bounds = task.getLaunchBounds();
- final Configuration config =
- mWindowManager.setAppTask(r.appToken, task.taskId, task.getLaunchBounds());
- if (config != null) {
- task.updateOverrideConfiguration(config, bounds);
- }
+ final Configuration config = task.updateOverrideConfiguration(mStackId, bounds);
+ mWindowManager.setAppTask(r.appToken, task.taskId, task.getLaunchBounds(), config);
r.taskConfigOverride = task.mOverrideConfig;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c86056b..33e0ef8 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -97,7 +97,6 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
-import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -334,6 +333,9 @@
// temp. rect used during resize calculation so we don't need to create a new object each time.
private final Rect tempRect = new Rect();
+ private final SparseArray<Configuration> mTmpConfigs = new SparseArray<>();
+ private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
+
/**
* Description of a request to start a new activity, which has been held
* due to app switches being disabled.
@@ -2917,19 +2919,19 @@
ActivityRecord r = stack.topRunningActivityLocked(null);
final boolean resizeTasks = r != null && r.task.mResizeable;
- final IntArray changedTaskIds = new IntArray(stack.numTasks());
- final List<Configuration> newTaskConfigs = new ArrayList<>(stack.numTasks());
- stack.mFullscreen = mWindowManager.resizeStack(
- stackId, bounds, resizeTasks, changedTaskIds, newTaskConfigs);
- for (int i = changedTaskIds.size() - 1; i >= 0; i--) {
- final TaskRecord task = anyTaskForIdLocked(changedTaskIds.get(i), false);
- if (task == null) {
- Slog.wtf(TAG, "Task in WindowManager, but not in ActivityManager???");
- continue;
+ mTmpBounds.clear();
+ mTmpConfigs.clear();
+ if (resizeTasks) {
+ ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ for (int i = tasks.size() - 1; i >= 0; i--) {
+ TaskRecord task = tasks.get(i);
+ task.updateOverrideConfiguration(stackId, bounds);
+ mTmpConfigs.put(task.taskId, task.mOverrideConfig);
+ mTmpBounds.put(task.taskId, task.mBounds);
}
- task.updateOverrideConfiguration(newTaskConfigs.get(i), bounds);
}
-
+ stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, resizeTasks, mTmpConfigs,
+ mTmpBounds);
if (stack.mStackId == DOCKED_STACK_ID) {
// Dock stack funness...Yay!
if (stack.mFullscreen) {
@@ -3024,25 +3026,27 @@
stackId = FREEFORM_WORKSPACE_STACK_ID;
}
if (stackId != task.stack.mStackId) {
- final String reason = "resizeTask";
- final ActivityStack stack =
- moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, reason);
+ moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, "resizeTask");
}
- final Configuration overrideConfig = mWindowManager.resizeTask(task.taskId, bounds);
- if (task.updateOverrideConfiguration(overrideConfig, bounds)) {
+ final Configuration overrideConfig = task.updateOverrideConfiguration(stackId, bounds);
+ // This variable holds information whether the configuration didn't change in a signficant
+ // way and the activity was kept the way it was. If it's false, it means the activity had
+ // to be relaunched due to configuration change.
+ boolean kept = true;
+ if (overrideConfig != null) {
ActivityRecord r = task.topRunningActivityLocked(null);
if (r != null) {
final ActivityStack stack = task.stack;
- final boolean updated = stack.ensureActivityConfigurationLocked(r, 0);
- // And we need to make sure at this point that all other activities
- // are made visible with the correct configuration.
+ kept = stack.ensureActivityConfigurationLocked(r, 0);
+ // All other activities must be made visible with their correct configuration.
ensureActivitiesVisibleLocked(r, 0);
- if (!updated) {
+ if (!kept) {
resumeTopActivitiesLocked(stack, null, null);
}
}
}
+ mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept);
}
ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
diff --git a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
index 5c4fd13..735c06f 100644
--- a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
+++ b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -234,7 +235,7 @@
break;
}
}
- task.setInitialBounds(proposal);
+ task.updateOverrideConfiguration(FREEFORM_WORKSPACE_STACK_ID, proposal);
}
private boolean shiftedToFar(Rect start, int shiftPolicy) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 9cbaec5..12c7b86 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -20,6 +20,7 @@
import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.HOME_STACK_ID;
+import static android.app.ActivityManager.INVALID_STACK_ID;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
@@ -52,6 +53,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionSession;
+import android.util.DisplayMetrics;
import android.util.Slog;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.util.XmlUtils;
@@ -63,6 +65,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Objects;
final class TaskRecord {
private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
@@ -106,6 +109,13 @@
static final int INVALID_TASK_ID = -1;
+ // The height/width divide used when fitting a task within a bounds with method
+ // {@link #fitWithinBounds}.
+ // We always want the task to to be visible in the bounds without affecting its size when
+ // fitting. To make sure this is the case, we don't adjust the task left or top side pass
+ // the input bounds right or bottom side minus the width or height divided by this value.
+ private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3;
+
final int taskId; // Unique identifier for this task.
String affinity; // The affinity name for this task, or null; may change identity.
String rootAffinity; // Initial base affinity, or null; does not change from initial root.
@@ -218,6 +228,8 @@
Configuration mOverrideConfig = Configuration.EMPTY;
+ private Rect mTmpRect = new Rect();
+
TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
mService = service;
@@ -271,8 +283,7 @@
long _firstActiveTime, long _lastActiveTime, long lastTimeMoved,
boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor,
- int callingUid, String callingPackage, boolean resizeable, boolean privileged,
- Rect bounds) {
+ int callingUid, String callingPackage, boolean resizeable, boolean privileged) {
mService = service;
mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
TaskPersister.IMAGE_EXTENSION;
@@ -309,7 +320,6 @@
mCallingPackage = callingPackage;
mResizeable = resizeable;
mPrivileged = privileged;
- mBounds = mLastNonFullscreenBounds = bounds;
}
void touchActiveTime() {
@@ -1163,7 +1173,8 @@
autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor,
- callingUid, callingPackage, resizeable, privileged, bounds);
+ callingUid, callingPackage, resizeable, privileged);
+ task.updateOverrideConfiguration(INVALID_STACK_ID, bounds);
for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
activities.get(activityNdx).task = task;
@@ -1173,25 +1184,51 @@
return task;
}
- boolean updateOverrideConfiguration(Configuration newConfig, Rect bounds) {
+ /**
+ * Update task's override configuration based on the bounds.
+ * @return Update configuration or null if there is no change.
+ */
+ Configuration updateOverrideConfiguration(int stackId, Rect bounds) {
+ if (stackId == FREEFORM_WORKSPACE_STACK_ID) {
+ // For freeform stack we don't adjust the size of the tasks to match that of the
+ // stack, but we do try to make sure the tasks are still contained with the
+ // bounds of the stack.
+ bounds = fitWithinBounds(bounds);
+ }
+ if (Objects.equals(mBounds, bounds)) {
+ return null;
+ }
Configuration oldConfig = mOverrideConfig;
- mOverrideConfig = (newConfig == null) ? Configuration.EMPTY : newConfig;
- // We override the configuration only when the task's dimensions are different from the
- // display. In this manner, we know that if the override configuration is empty, the task
- // is necessarily fullscreen.
- mFullscreen = Configuration.EMPTY.equals(mOverrideConfig);
+
+ mFullscreen = bounds == null;
if (mFullscreen) {
if (mBounds != null && stack.mStackId != DOCKED_STACK_ID) {
mLastNonFullscreenBounds = mBounds;
}
mBounds = null;
+ mOverrideConfig = Configuration.EMPTY;
} else {
mBounds = new Rect(bounds);
if (stack.mStackId != DOCKED_STACK_ID) {
mLastNonFullscreenBounds = mBounds;
}
+
+ final Configuration serviceConfig = mService.mConfiguration;
+ mOverrideConfig = new Configuration(serviceConfig);
+ // TODO(multidisplay): Update Dp to that of display stack is on.
+ final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ mOverrideConfig.screenWidthDp =
+ Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp);
+ mOverrideConfig.screenHeightDp =
+ Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
+ mOverrideConfig.smallestScreenWidthDp =
+ Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
+ mOverrideConfig.orientation =
+ (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
+ ? Configuration.ORIENTATION_PORTRAIT
+ : Configuration.ORIENTATION_LANDSCAPE;
}
- return !mOverrideConfig.equals(oldConfig);
+ return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
}
/** Returns the stack that should be used to launch this task. */
@@ -1225,12 +1262,39 @@
return mLastNonFullscreenBounds;
}
- void setInitialBounds(Rect rect) {
- if (mBounds == null) {
- mBounds = new Rect();
+ /** Fits the tasks within the input bounds adjusting the task bounds as needed.
+ * @param bounds Bounds to fit the task within. Nothing is done if null.
+ * @return Returns final configuration after updating with the adjusted bounds.
+ * */
+ Rect fitWithinBounds(Rect bounds) {
+ if (bounds == null || mBounds == null || bounds.contains(mBounds)) {
+ return bounds;
}
- mBounds.set(rect);
- mLastNonFullscreenBounds = mBounds;
+ mTmpRect.set(mBounds);
+
+ if (mBounds.left < bounds.left || mBounds.right > bounds.right) {
+ final int maxRight = bounds.right - (bounds.width() / FIT_WITHIN_BOUNDS_DIVIDER);
+ int horizontalDiff = bounds.left - mBounds.left;
+ if ((horizontalDiff < 0 && mBounds.left >= maxRight)
+ || (mBounds.left + horizontalDiff >= maxRight)) {
+ horizontalDiff = maxRight - mBounds.left;
+ }
+ mTmpRect.left += horizontalDiff;
+ mTmpRect.right += horizontalDiff;
+ }
+
+ if (mBounds.top < bounds.top || mBounds.bottom > bounds.bottom) {
+ final int maxBottom = bounds.bottom - (bounds.height() / FIT_WITHIN_BOUNDS_DIVIDER);
+ int verticalDiff = bounds.top - mBounds.top;
+ if ((verticalDiff < 0 && mBounds.top >= maxBottom)
+ || (mBounds.top + verticalDiff >= maxBottom)) {
+ verticalDiff = maxBottom - mBounds.top;
+ }
+ mTmpRect.top += verticalDiff;
+ mTmpRect.bottom += verticalDiff;
+ }
+
+ return mTmpRect;
}
void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 7e46db8..cbb3c39 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -24,7 +24,9 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
import android.os.Binder;
+import android.os.DeadObjectException;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
@@ -51,7 +53,6 @@
import android.hardware.fingerprint.IFingerprintDaemon;
import android.hardware.fingerprint.IFingerprintDaemonCallback;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
-import android.view.Display;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
@@ -60,6 +61,7 @@
import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -83,6 +85,8 @@
private ClientMonitor mAuthClient = null;
private ClientMonitor mEnrollClient = null;
private ClientMonitor mRemoveClient = null;
+ private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
+ new ArrayList<>();
private final AppOpsManager mAppOps;
private static final long MS_PER_SEC = 1000;
@@ -259,6 +263,7 @@
// If we're asked to reset failed attempts externally (i.e. from Keyguard), the runnable
// may still be in the queue; remove it.
mHandler.removeCallbacks(mLockoutReset);
+ notifyLockoutResetMonitors();
}
private boolean handleFailedAttempt(ClientMonitor clientMonitor) {
@@ -499,6 +504,23 @@
opPackageName) == AppOpsManager.MODE_ALLOWED;
}
+ private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) {
+ if (!mLockoutMonitors.contains(monitor)) {
+ mLockoutMonitors.add(monitor);
+ }
+ }
+
+ private void removeLockoutResetCallback(
+ FingerprintServiceLockoutResetMonitor monitor) {
+ mLockoutMonitors.remove(monitor);
+ }
+
+ private void notifyLockoutResetMonitors() {
+ for (int i = 0; i < mLockoutMonitors.size(); i++) {
+ mLockoutMonitors.get(i).sendLockoutReset();
+ }
+ }
+
private class ClientMonitor implements IBinder.DeathRecipient {
IBinder token;
IFingerprintServiceReceiver receiver;
@@ -614,7 +636,7 @@
FingerprintUtils.vibrateFingerprintSuccess(getContext());
}
result |= true; // we have a valid fingerprint
- mLockoutReset.run();
+ mHandler.post(mLockoutReset);
}
return result;
}
@@ -654,6 +676,36 @@
}
}
+ private class FingerprintServiceLockoutResetMonitor {
+
+ private final IFingerprintServiceLockoutResetCallback mCallback;
+
+ public FingerprintServiceLockoutResetMonitor(
+ IFingerprintServiceLockoutResetCallback callback) {
+ mCallback = callback;
+ }
+
+ public void sendLockoutReset() {
+ if (mCallback != null) {
+ try {
+ mCallback.onLockoutReset(mHalDeviceId);
+ } catch (DeadObjectException e) {
+ Slog.w(TAG, "Death object while invoking onLockoutReset: ", e);
+ mHandler.post(mRemoveCallbackRunnable);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to invoke onLockoutReset: ", e);
+ }
+ }
+ }
+
+ private final Runnable mRemoveCallbackRunnable = new Runnable() {
+ @Override
+ public void run() {
+ removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
+ }
+ };
+ }
+
private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() {
@Override
@@ -922,7 +974,19 @@
public void resetTimeout(byte [] token) {
checkPermission(RESET_FINGERPRINT_LOCKOUT);
// TODO: confirm security token when we move timeout management into the HAL layer.
- mLockoutReset.run();
+ mHandler.post(mLockoutReset);
+ }
+
+ @Override
+ public void addLockoutResetCallback(final IFingerprintServiceLockoutResetCallback callback)
+ throws RemoteException {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ addLockoutResetMonitor(
+ new FingerprintServiceLockoutResetMonitor(callback));
+ }
+ });
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 0a12d5a..cbe61c3 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -46,7 +46,6 @@
import android.service.notification.ZenModeConfig.EventInfo;
import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.service.notification.ZenModeConfig.ZenRule;
-import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
@@ -149,6 +148,7 @@
mAudioManager.setRingerModeDelegate(mRingerModeDelegate);
}
mHandler.postMetricsTimer();
+ evaluateZenMode("onSystemReady", true);
}
public void onUserSwitched(int user) {
@@ -330,13 +330,14 @@
}
mConditions.evaluateConfig(config, false /*processSubscriptions*/); // may modify config
mConfigs.put(config.user, config);
- if (config.equals(mConfig)) return true;
if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable());
ZenLog.traceConfig(reason, mConfig, config);
final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
getNotificationPolicy(config));
mConfig = config;
- dispatchOnConfigChanged();
+ if (config.equals(mConfig)) {
+ dispatchOnConfigChanged();
+ }
if (policyChanged){
dispatchOnPolicyChanged();
}
@@ -370,9 +371,7 @@
private boolean evaluateZenMode(String reason, boolean setRingerMode) {
if (DEBUG) Log.d(TAG, "evaluateZenMode");
- final ArraySet<ZenRule> automaticRules = new ArraySet<ZenRule>();
- final int zen = computeZenMode(automaticRules);
- if (zen == mZenMode) return false;
+ final int zen = computeZenMode();
ZenLog.traceSetZenMode(zen, reason);
mZenMode = zen;
updateRingerModeAffectedStreams();
@@ -381,7 +380,9 @@
applyZenToRingerMode();
}
applyRestrictions();
- mHandler.postDispatchOnZenModeChanged();
+ if (zen != mZenMode) {
+ mHandler.postDispatchOnZenModeChanged();
+ }
return true;
}
@@ -391,7 +392,7 @@
}
}
- private int computeZenMode(ArraySet<ZenRule> automaticRulesOut) {
+ private int computeZenMode() {
if (mConfig == null) return Global.ZEN_MODE_OFF;
if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
int zen = Global.ZEN_MODE_OFF;
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index c75a1d3..66170d4 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -136,9 +136,6 @@
case "signer":
policies.add(readSignerOrThrow(parser));
break;
- case "default":
- policies.add(readDefaultOrThrow(parser));
- break;
default:
skip(parser);
}
@@ -233,45 +230,6 @@
}
/**
- * Loop over a default element looking for seinfo child tags. A {@link Policy}
- * instance will be created and returned in the process. All other tags encountered
- * will be skipped.
- *
- * @param parser an XmlPullParser object representing a default element.
- * @return the constructed {@link Policy} instance
- * @throws IOException
- * @throws XmlPullParserException
- * @throws IllegalArgumentException if any of the validation checks fail while
- * parsing tag values.
- * @throws IllegalStateException if any of the invariants fail when constructing
- * the {@link Policy} instance.
- */
- private static Policy readDefaultOrThrow(XmlPullParser parser) throws IOException,
- XmlPullParserException {
-
- parser.require(XmlPullParser.START_TAG, null, "default");
- Policy.PolicyBuilder pb = new Policy.PolicyBuilder();
- pb.setAsDefaultPolicy();
-
- while (parser.next() != XmlPullParser.END_TAG) {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
-
- String tagName = parser.getName();
- if ("seinfo".equals(tagName)) {
- String seinfo = parser.getAttributeValue(null, "value");
- pb.setGlobalSeinfoOrThrow(seinfo);
- readSeinfo(parser);
- } else {
- skip(parser);
- }
- }
-
- return pb.build();
- }
-
- /**
* Loop over a package element looking for seinfo child tags. If found return the
* value attribute of the seinfo tag, otherwise return null. All other tags encountered
* will be skipped.
@@ -337,35 +295,28 @@
/**
* Applies a security label to a package based on an seinfo tag taken from a matched
- * policy. All signature based policy stanzas are consulted first and, if no match
- * is found, the default policy stanza is then consulted. The security label is
- * attached to the ApplicationInfo instance of the package in the event that a matching
- * policy was found.
+ * policy. All signature based policy stanzas are consulted and, if no match is
+ * found, the default seinfo label of 'default' (set in ApplicationInfo object) is
+ * used. The security label is attached to the ApplicationInfo instance of the package
+ * in the event that a matching policy was found.
*
* @param pkg object representing the package to be labeled.
- * @return boolean which determines whether a non null seinfo label was assigned
- * to the package. A null value simply represents that no policy matched.
*/
- public static boolean assignSeinfoValue(PackageParser.Package pkg) {
+ public static void assignSeinfoValue(PackageParser.Package pkg) {
synchronized (sPolicies) {
for (Policy policy : sPolicies) {
String seinfo = policy.getMatchedSeinfo(pkg);
if (seinfo != null) {
pkg.applicationInfo.seinfo = seinfo;
- if (DEBUG_POLICY_INSTALL) {
- Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
- "seinfo=" + seinfo);
- }
- return true;
+ break;
}
}
}
if (DEBUG_POLICY_INSTALL) {
- Slog.i(TAG, "package (" + pkg.packageName + ") doesn't match any policy; " +
- "seinfo will remain null");
+ Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
+ "seinfo=" + pkg.applicationInfo.seinfo);
}
- return false;
}
/**
@@ -506,30 +457,16 @@
* .build();
* }
* </pre>
- * <p>
- * The following is an example of how to use {@link Policy.PolicyBuilder} to create a
- * default based Policy instance.
- * </p>
- * <pre>
- * {@code
- * Policy policy = new Policy.PolicyBuilder()
- * .setAsDefaultPolicy()
- * .setGlobalSeinfoOrThrow("default")
- * .build();
- * }
- * </pre>
*/
final class Policy {
private final String mSeinfo;
- private final boolean mDefaultStanza;
private final Set<Signature> mCerts;
private final Map<String, String> mPkgMap;
// Use the PolicyBuilder pattern to instantiate
private Policy(PolicyBuilder builder) {
mSeinfo = builder.mSeinfo;
- mDefaultStanza = builder.mDefaultStanza;
mCerts = Collections.unmodifiableSet(builder.mCerts);
mPkgMap = Collections.unmodifiableMap(builder.mPkgMap);
}
@@ -545,15 +482,6 @@
}
/**
- * Return whether this policy object represents a default stanza.
- *
- * @return A boolean indicating if this object represents a default policy stanza.
- */
- public boolean isDefaultStanza() {
- return mDefaultStanza;
- }
-
- /**
* Return whether this policy object contains package name mapping refinements.
*
* @return A boolean indicating if this object has inner package name mappings.
@@ -584,10 +512,6 @@
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- if (mDefaultStanza) {
- sb.append("defaultStanza=true ");
- }
-
for (Signature cert : mCerts) {
sb.append("cert=" + cert.toCharsString().substring(0, 11) + "... ");
}
@@ -609,22 +533,15 @@
* is determined using the following steps:
* </p>
* <ul>
- * <li> If this Policy instance is defined as a default stanza:
- * <ul><li>Return the global seinfo value</li></ul>
+ * <li> All certs used to sign the apk and all certs stored with this policy
+ * instance are tested for set equality. If this fails then null is returned.
* </li>
- * <li> If this Policy instance is defined as a signer stanza:
- * <ul>
- * <li> All certs used to sign the apk and all certs stored with this policy
- * instance are tested for set equality. If this fails then null is returned.
- * </li>
- * <li> If all certs match then an appropriate inner package stanza is
- * searched based on package name alone. If matched, the stored seinfo
- * value for that mapping is returned.
- * </li>
- * <li> If all certs matched and no inner package stanza matches then return
- * the global seinfo value. The returned value can be null in this case.
- * </li>
- * </ul>
+ * <li> If all certs match then an appropriate inner package stanza is
+ * searched based on package name alone. If matched, the stored seinfo
+ * value for that mapping is returned.
+ * </li>
+ * <li> If all certs matched and no inner package stanza matches then return
+ * the global seinfo value. The returned value can be null in this case.
* </li>
* </ul>
* <p>
@@ -636,37 +553,34 @@
* A value of null can also be returned if no match occured.
*/
public String getMatchedSeinfo(PackageParser.Package pkg) {
- if (!mDefaultStanza) {
- // Check for exact signature matches across all certs.
- Signature[] certs = mCerts.toArray(new Signature[0]);
- if (!Signature.areExactMatch(certs, pkg.mSignatures)) {
- return null;
- }
-
- // Check for inner package name matches given that the
- // signature checks already passed.
- String seinfoValue = mPkgMap.get(pkg.packageName);
- if (seinfoValue != null) {
- return seinfoValue;
- }
+ // Check for exact signature matches across all certs.
+ Signature[] certs = mCerts.toArray(new Signature[0]);
+ if (!Signature.areExactMatch(certs, pkg.mSignatures)) {
+ return null;
}
- // Return the global seinfo value (even if it's null).
+ // Check for inner package name matches given that the
+ // signature checks already passed.
+ String seinfoValue = mPkgMap.get(pkg.packageName);
+ if (seinfoValue != null) {
+ return seinfoValue;
+ }
+
+ // Return the global seinfo value.
return mSeinfo;
}
/**
* A nested builder class to create {@link Policy} instances. A {@link Policy}
* class instance represents one valid policy stanza found in a mac_permissions.xml
- * file. A valid policy stanza is defined to be either a signer or default stanza
- * which obeys the rules outlined in external/sepolicy/mac_permissions.xml. The
- * {@link #build} method ensures a set of invariants are upheld enforcing the correct
- * stanza structure before returning a valid Policy object.
+ * file. A valid policy stanza is defined to be a signer stanza which obeys the rules
+ * outlined in external/sepolicy/mac_permissions.xml. The {@link #build} method
+ * ensures a set of invariants are upheld enforcing the correct stanza structure
+ * before returning a valid Policy object.
*/
public static final class PolicyBuilder {
private String mSeinfo;
- private boolean mDefaultStanza;
private final Set<Signature> mCerts;
private final Map<String, String> mPkgMap;
@@ -676,19 +590,6 @@
}
/**
- * Sets this stanza as a default stanza. All policy stanzas are assumed to
- * be signer stanzas unless this method is explicitly called. Default stanzas
- * are treated differently with respect to allowable child tags, ordering and
- * when and how policy decisions are enforced.
- *
- * @return The reference to this PolicyBuilder.
- */
- public PolicyBuilder setAsDefaultPolicy() {
- mDefaultStanza = true;
- return this;
- }
-
- /**
* Adds a signature to the set of certs used for validation checks. The purpose
* being that all contained certs will need to be matched against all certs
* contained with an apk.
@@ -710,11 +611,8 @@
/**
* Set the global seinfo tag for this policy stanza. The global seinfo tag
- * represents the seinfo element that is used in one of two ways depending on
- * its context. When attached to a signer tag the global seinfo represents an
- * assignment when there isn't a further inner package refinement in policy.
- * When used with a default tag, it represents the only allowable assignment
- * value.
+ * when attached to a signer tag represents the assignment when there isn't a
+ * further inner package refinement in policy.
*
* @param seinfo the seinfo value given as a String.
* @return The reference to this PolicyBuilder.
@@ -740,9 +638,7 @@
/**
* Create a package name to seinfo value mapping. Each mapping represents
* the seinfo value that will be assigned to the described package name.
- * These localized mappings allow the global seinfo to be overriden. This
- * mapping provides no value when used in conjunction with a default stanza;
- * enforced through the {@link #build} method.
+ * These localized mappings allow the global seinfo to be overriden.
*
* @param pkgName the android package name given to the app
* @param seinfo the seinfo value that will be assigned to the passed pkgName
@@ -799,51 +695,25 @@
* about the expected structure of a policy stanza.
* Those invariants are:
* </p>
- * <ul>
- * <li> If a default stanza
- * <ul>
- * <li> an attached global seinfo tag must be present </li>
- * <li> no signatures and no package names can be present </li>
- * </ul>
- * </li>
- * <li> If a signer stanza
- * <ul>
- * <li> at least one cert must be found </li>
- * <li> either a global seinfo value is present OR at least one
- * inner package mapping must be present BUT not both. </li>
- * </ul>
- * </li>
- * </ul>
- *
+ * <ul>
+ * <li> at least one cert must be found </li>
+ * <li> either a global seinfo value is present OR at least one
+ * inner package mapping must be present BUT not both. </li>
+ * </ul>
* @return an instance of {@link Policy} with the options set from this builder
* @throws IllegalStateException if an invariant is violated.
*/
public Policy build() {
Policy p = new Policy(this);
- if (p.mDefaultStanza) {
- if (p.mSeinfo == null) {
- String err = "Missing global seinfo tag with default stanza.";
- throw new IllegalStateException(err);
- }
- if (p.mCerts.size() != 0) {
- String err = "Certs not allowed with default stanza.";
- throw new IllegalStateException(err);
- }
- if (!p.mPkgMap.isEmpty()) {
- String err = "Inner package mappings not allowed with default stanza.";
- throw new IllegalStateException(err);
- }
- } else {
- if (p.mCerts.size() == 0) {
- String err = "Missing certs with signer tag. Expecting at least one.";
- throw new IllegalStateException(err);
- }
- if (!(p.mSeinfo == null ^ p.mPkgMap.isEmpty())) {
- String err = "Only seinfo tag XOR package tags are allowed within " +
- "a signer stanza.";
- throw new IllegalStateException(err);
- }
+ if (p.mCerts.isEmpty()) {
+ String err = "Missing certs with signer tag. Expecting at least one.";
+ throw new IllegalStateException(err);
+ }
+ if (!(p.mSeinfo == null ^ p.mPkgMap.isEmpty())) {
+ String err = "Only seinfo tag XOR package tags are allowed within " +
+ "a signer stanza.";
+ throw new IllegalStateException(err);
}
return p;
@@ -858,7 +728,6 @@
* <ul>
* <li> signer stanzas with inner package mappings </li>
* <li> signer stanzas with global seinfo tags </li>
- * <li> default stanza </li>
* </ul>
* This comparison also checks for duplicate entries on the input selectors. Any
* found duplicates will be flagged and can be checked with {@link #foundDuplicate}.
@@ -875,11 +744,6 @@
@Override
public int compare(Policy p1, Policy p2) {
- // Give precedence to signature stanzas over default stanzas
- if (p1.isDefaultStanza() != p2.isDefaultStanza()) {
- return p1.isDefaultStanza() ? 1 : -1;
- }
-
// Give precedence to stanzas with inner package mappings
if (p1.hasInnerPackages() != p2.hasInnerPackages()) {
return p1.hasInnerPackages() ? -1 : 1;
@@ -887,7 +751,7 @@
// Check for duplicate entries
if (p1.getSignatures().equals(p2.getSignatures())) {
- // Checks if default stanza or a signer w/o inner package names
+ // Checks if signer w/o inner package names
if (p1.hasGlobalSeinfo()) {
duplicateFound = true;
Slog.e(SELinuxMMAC.TAG, "Duplicate policy entry: " + p1.toString());
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 9ddbcca..48e205f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4462,7 +4462,7 @@
if (mAppsToBeHidden.isEmpty()) {
if (dismissKeyguard && !mKeyguardSecure) {
mAppsThatDismissKeyguard.add(appToken);
- } else if (win.isDrawnLw()) {
+ } else if (win.isDrawnLw() || win.hasAppShownWindows()) {
mWinShowWhenLocked = win;
mHideLockScreen = true;
mForceStatusBarFromKeyguard = false;
@@ -4496,7 +4496,8 @@
mWinDismissingKeyguard = win;
mSecureDismissingKeyguard = mKeyguardSecure;
mForceStatusBarFromKeyguard = mShowingLockscreen && mKeyguardSecure;
- } else if (mAppsToBeHidden.isEmpty() && showWhenLocked && win.isDrawnLw()) {
+ } else if (mAppsToBeHidden.isEmpty() && showWhenLocked
+ && (win.isDrawnLw() || win.hasAppShownWindows())) {
if (DEBUG_LAYOUT) Slog.v(TAG,
"Setting mHideLockScreen to true by win " + win);
mHideLockScreen = true;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 554af28..666d902 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -23,7 +23,6 @@
import android.content.res.Configuration;
import android.graphics.Rect;
-import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseArray;
@@ -41,13 +40,6 @@
* when no window animation is driving it. */
private static final int DEFAULT_DIM_DURATION = 200;
- // The amount we divide the height/width of the bounds we are trying to fit the task within
- // when using the method {@link #fitWithinBounds}.
- // We always want the task to to be visible in the bounds without affecting its size when
- // fitting. To make sure this is the case, we don't adjust the task left or top side pass
- // the input bounds right or bottom side minus the width or height divided by this value.
- private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3;
-
TaskStack mStack;
final AppTokenList mAppTokens = new AppTokenList();
final int mTaskId;
@@ -84,13 +76,13 @@
// of creating a new object per fullscreen task on a display.
private static final SparseArray<DimLayer> sSharedFullscreenDimLayers = new SparseArray<>();
- Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds) {
+ Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
+ Configuration config) {
mTaskId = taskId;
mStack = stack;
mUserId = userId;
mService = service;
- mOverrideConfig = Configuration.EMPTY;
- setBounds(bounds);
+ setBounds(bounds, config);
}
DisplayContent getDisplayContent() {
@@ -172,43 +164,18 @@
}
}
- /** Fits the tasks within the input bounds adjusting the task bounds as needed.
- * @param bounds Bounds to fit the task within. Nothing is done if null.
- * @return Returns true if the task bounds was adjusted in any way.
- * */
- boolean fitWithinBounds(Rect bounds) {
- if (bounds == null || bounds.contains(mBounds)) {
- return false;
- }
- mTmpRect2.set(mBounds);
-
- if (mBounds.left < bounds.left || mBounds.right > bounds.right) {
- final int maxRight = bounds.right - (bounds.width() / FIT_WITHIN_BOUNDS_DIVIDER);
- int horizontalDiff = bounds.left - mBounds.left;
- if ((horizontalDiff < 0 && mBounds.left >= maxRight)
- || (mBounds.left + horizontalDiff >= maxRight)) {
- horizontalDiff = maxRight - mBounds.left;
- }
- mTmpRect2.left += horizontalDiff;
- mTmpRect2.right += horizontalDiff;
- }
-
- if (mBounds.top < bounds.top || mBounds.bottom > bounds.bottom) {
- final int maxBottom = bounds.bottom - (bounds.height() / FIT_WITHIN_BOUNDS_DIVIDER);
- int verticalDiff = bounds.top - mBounds.top;
- if ((verticalDiff < 0 && mBounds.top >= maxBottom)
- || (mBounds.top + verticalDiff >= maxBottom)) {
- verticalDiff = maxBottom - mBounds.top;
- }
- mTmpRect2.top += verticalDiff;
- mTmpRect2.bottom += verticalDiff;
- }
-
- return setBounds(mTmpRect2);
- }
-
/** Set the task bounds. Passing in null sets the bounds to fullscreen. */
- boolean setBounds(Rect bounds) {
+ boolean setBounds(Rect bounds, Configuration config) {
+ if (config == null) {
+ config = Configuration.EMPTY;
+ }
+ if (bounds == null && !Configuration.EMPTY.equals(config)) {
+ throw new IllegalArgumentException("null bounds but non empty configuration: "
+ + config);
+ }
+ if (bounds != null && Configuration.EMPTY.equals(config)) {
+ throw new IllegalArgumentException("non null bounds, but empty configuration");
+ }
boolean oldFullscreen = mFullscreen;
int rotation = Surface.ROTATION_0;
final DisplayContent displayContent = mStack.getDisplayContent();
@@ -241,7 +208,7 @@
mBounds.set(bounds);
mRotation = rotation;
updateDimLayer();
- updateOverrideConfiguration();
+ mOverrideConfig = mFullscreen ? Configuration.EMPTY : config;
return true;
}
@@ -249,36 +216,12 @@
out.set(mBounds);
}
- private void updateOverrideConfiguration() {
- final Configuration serviceConfig = mService.mCurConfiguration;
- if (mFullscreen) {
- mOverrideConfig = Configuration.EMPTY;
- return;
- }
-
- if (mOverrideConfig == Configuration.EMPTY) {
- mOverrideConfig = new Configuration();
- }
-
- // TODO(multidisplay): Update Dp to that of display stack is on.
- final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
- mOverrideConfig.screenWidthDp =
- Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp);
- mOverrideConfig.screenHeightDp =
- Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
- mOverrideConfig.smallestScreenWidthDp =
- Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
- mOverrideConfig.orientation =
- (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
- ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
- }
-
void updateDisplayInfo(final DisplayContent displayContent) {
if (displayContent == null) {
return;
}
if (mFullscreen) {
- setBounds(null);
+ setBounds(null, Configuration.EMPTY);
return;
}
final int newRotation = displayContent.getDisplayInfo().rotation;
@@ -313,7 +256,7 @@
mTmpRect2.bottom = mTmpRect2.top + mBounds.width();
break;
}
- setBounds(mTmpRect2);
+ setBounds(mTmpRect2, mOverrideConfig);
}
/** Updates the dim layer bounds, recreating it if needed. */
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 25a71d9..a7ef2f8 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -27,6 +27,7 @@
import android.util.EventLog;
import android.util.IntArray;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.DisplayInfo;
import com.android.server.EventLogTags;
@@ -96,15 +97,15 @@
/**
* Set the bounds of the stack and its containing tasks.
- * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
+ * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
* @param resizeTasks If true, the tasks within the stack will also be resized.
- * @param changedTaskIds Output list of Ids of tasks that changed in bounds.
- * @param newTaskConfigs Output list of new Configuation of the tasks that changed.
+ * @param configs Configuration for individual tasks, keyed by task id.
+ * @param taskBounds Bounds for individual tasks, keyed by task id.
* @return True if the stack bounds was changed.
* */
- boolean setBounds(Rect bounds, boolean resizeTasks, IntArray changedTaskIds,
- List<Configuration> newTaskConfigs) {
- if (!setBounds(bounds)) {
+ boolean setBounds(Rect stackBounds, boolean resizeTasks, SparseArray<Configuration> configs,
+ SparseArray<Rect> taskBounds) {
+ if (!setBounds(stackBounds)) {
return false;
}
@@ -113,20 +114,17 @@
}
// Update bounds of containing tasks.
- final Rect newBounds = mFullscreen ? null : mBounds;
for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
final Task task = mTasks.get(taskNdx);
- if (mStackId == FREEFORM_WORKSPACE_STACK_ID) {
- // For freeform stack we don't adjust the size of the tasks to match that of the
- // stack, but we do try to make sure the tasks are still contained with the
- // bounds of the stack.
- if (task.fitWithinBounds(newBounds)) {
- changedTaskIds.add(task.mTaskId);
- newTaskConfigs.add(task.mOverrideConfig);
+ Configuration config = configs.get(task.mTaskId);
+ if (config != null) {
+ Rect bounds = taskBounds.get(task.mTaskId);
+ if (bounds == null) {
+ bounds = stackBounds;
}
- } else if (task.setBounds(newBounds)) {
- changedTaskIds.add(task.mTaskId);
- newTaskConfigs.add(task.mOverrideConfig);
+ task.setBounds(bounds, config);
+ } else {
+ Slog.wtf(TAG, "No config for task: " + task + ", is there a mismatch with AM?");
}
}
return true;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index cf690a5..bf7d1e7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3041,8 +3041,8 @@
Binder.restoreCallingIdentity(origId);
}
- private Task createTaskLocked(
- int taskId, int stackId, int userId, AppWindowToken atoken, Rect bounds) {
+ private Task createTaskLocked(int taskId, int stackId, int userId, AppWindowToken atoken,
+ Rect bounds, Configuration config) {
if (DEBUG_STACK) Slog.i(TAG, "createTaskLocked: taskId=" + taskId + " stackId=" + stackId
+ " atoken=" + atoken + " bounds=" + bounds);
final TaskStack stack = mStackIdToStack.get(stackId);
@@ -3050,17 +3050,17 @@
throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
}
EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);
- Task task = new Task(taskId, stack, userId, this, bounds);
+ Task task = new Task(taskId, stack, userId, this, bounds, config);
mTaskIdToTask.put(taskId, task);
stack.addTask(task, !atoken.mLaunchTaskBehind /* toTop */, atoken.showForAllUsers);
return task;
}
@Override
- public Configuration addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
+ public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
- Rect taskBounds) {
+ Rect taskBounds, Configuration config) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3084,7 +3084,7 @@
AppWindowToken atoken = findAppWindowToken(token.asBinder());
if (atoken != null) {
Slog.w(TAG, "Attempted to add existing app token: " + token);
- return null;
+ return;
}
atoken = new AppWindowToken(this, token, voiceInteraction);
atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
@@ -3098,10 +3098,8 @@
+ " to stack=" + stackId + " task=" + taskId + " at " + addPos);
Task task = mTaskIdToTask.get(taskId);
- Configuration outConfig = null;
if (task == null) {
- task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds);
- outConfig = task.mOverrideConfig;
+ task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds, config);
}
task.addAppToken(addPos, atoken);
@@ -3110,13 +3108,11 @@
// Application tokens start out hidden.
atoken.hidden = true;
atoken.hiddenRequested = true;
-
- return outConfig;
}
}
@Override
- public Configuration setAppTask(IBinder token, int taskId, Rect taskBounds) {
+ public void setAppTask(IBinder token, int taskId, Rect taskBounds, Configuration config) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setAppTask()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3126,20 +3122,18 @@
final AppWindowToken atoken = findAppWindowToken(token);
if (atoken == null) {
Slog.w(TAG, "Attempted to set task id of non-existing app token: " + token);
- return null;
+ return;
}
final Task oldTask = atoken.mTask;
oldTask.removeAppToken(atoken);
Task newTask = mTaskIdToTask.get(taskId);
- Configuration outConfig = null;
if (newTask == null) {
newTask = createTaskLocked(
- taskId, oldTask.mStack.mStackId, oldTask.mUserId, atoken, taskBounds);
- outConfig = newTask.mOverrideConfig;
+ taskId, oldTask.mStack.mStackId, oldTask.mUserId, atoken, taskBounds,
+ config);
}
newTask.addAppToken(Integer.MAX_VALUE /* at top */, atoken);
- return outConfig;
}
}
@@ -4599,19 +4593,19 @@
* @param stackId Id of stack to resize.
* @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
* @param resizeTasks If true, the tasks within the stack will also be resized.
- * @param changedTaskIds Output list of Ids of tasks that changed in bounds due to resize.
- * @param newTaskConfigs Output list of new Configuation of the tasks that changed.
+ * @param configs Configurations for tasks in the resized stack, keyed by task id.
+ * @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
* @return True if the stack is now fullscreen.
* */
public boolean resizeStack(int stackId, Rect bounds, boolean resizeTasks,
- IntArray changedTaskIds, List<Configuration> newTaskConfigs) {
+ SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) {
synchronized (mWindowMap) {
final TaskStack stack = mStackIdToStack.get(stackId);
if (stack == null) {
throw new IllegalArgumentException("resizeStack: stackId " + stackId
+ " not found.");
}
- if (stack.setBounds(bounds, resizeTasks, changedTaskIds, newTaskConfigs)) {
+ if (stack.setBounds(bounds, resizeTasks, configs, taskBounds)) {
stack.resizeWindows();
stack.getDisplayContent().layoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
@@ -4648,19 +4642,20 @@
* Returns a {@link Configuration} object that contains configurations settings
* that should be overridden due to the operation.
*/
- public Configuration resizeTask(int taskId, Rect bounds) {
+ public void resizeTask(int taskId, Rect bounds, Configuration configuration, boolean relayout) {
synchronized (mWindowMap) {
Task task = mTaskIdToTask.get(taskId);
if (task == null) {
throw new IllegalArgumentException("resizeTask: taskId " + taskId
+ " not found.");
}
- if (task.setBounds(bounds)) {
+ if (task.setBounds(bounds, configuration)) {
task.resizeWindows();
- task.getDisplayContent().layoutNeeded = true;
- performLayoutAndPlaceSurfacesLocked();
+ if (relayout) {
+ task.getDisplayContent().layoutNeeded = true;
+ performLayoutAndPlaceSurfacesLocked();
+ }
}
- return new Configuration(task.mOverrideConfig);
}
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 2d31a78..8a1a553 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -206,8 +206,14 @@
*/
public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
+ /**
+ * Call sends responses through connection.
+ * @hide
+ */
+ public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
+
//******************************************************************************************
- // Next CAPABILITY value: 0x00004000
+ // Next CAPABILITY value: 0x00800000
//******************************************************************************************
/**
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 7b277c5..430760a 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -248,8 +248,15 @@
*/
public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 0x00200000;
+ /**
+ * Indicates that the connection itself wants to handle any sort of reply response, rather than
+ * relying on SMS.
+ * @hide
+ */
+ public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
+
//**********************************************************************************************
- // Next CAPABILITY value: 0x00400000
+ // Next CAPABILITY value: 0x00800000
//**********************************************************************************************
/**
@@ -388,6 +395,10 @@
if (can(capabilities, CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) {
builder.append(" CAPABILITY_SINGLE_PARTY_CONFERENCE");
}
+ if (can(capabilities, CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
+ builder.append(" CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION");
+ }
+
builder.append("]");
return builder.toString();
}
@@ -1763,6 +1774,13 @@
public void onReject() {}
/**
+ * Notifies ths Connection of a request reject with a message.
+ *
+ * @hide
+ */
+ public void onReject(String replyMessage) {}
+
+ /**
* Notifies this Connection whether the user wishes to proceed with the post-dial DTMF codes.
*/
public void onPostDialContinue(boolean proceed) {}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 383e45b..4e330bdb 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -101,6 +101,7 @@
private static final int MSG_ANSWER_VIDEO = 17;
private static final int MSG_MERGE_CONFERENCE = 18;
private static final int MSG_SWAP_CONFERENCE = 19;
+ private static final int MSG_REJECT_WITH_MESSAGE = 20;
private static Connection sNullConnection;
@@ -166,6 +167,14 @@
}
@Override
+ public void rejectWithMessage(String callId, String message) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = message;
+ mHandler.obtainMessage(MSG_REJECT_WITH_MESSAGE, args).sendToTarget();
+ }
+
+ @Override
public void disconnect(String callId) {
mHandler.obtainMessage(MSG_DISCONNECT, callId).sendToTarget();
}
@@ -296,6 +305,15 @@
case MSG_REJECT:
reject((String) msg.obj);
break;
+ case MSG_REJECT_WITH_MESSAGE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ reject((String) args.arg1, (String) args.arg2);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
case MSG_DISCONNECT:
disconnect((String) msg.obj);
break;
@@ -681,6 +699,11 @@
findConnectionForAction(callId, "reject").onReject();
}
+ private void reject(String callId, String rejectWithMessage) {
+ Log.d(this, "reject %s with message", callId);
+ findConnectionForAction(callId, "reject").onReject(rejectWithMessage);
+ }
+
private void disconnect(String callId) {
Log.d(this, "disconnect %s", callId);
if (mConnectionById.containsKey(callId)) {
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index c2e8530..dd253cf 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -50,6 +50,8 @@
void reject(String callId);
+ void rejectWithMessage(String callId, String message);
+
void disconnect(String callId);
void hold(String callId);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index bfb7a50..aa750ef 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -419,6 +419,15 @@
public static final String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl";
public static final String KEY_MMS_USER_AGENT_STRING = "userAgent";
+ /**
+ * Determines whether the carrier supports making non-emergency phone calls while the phone is
+ * in emergency callback mode. Default value is {@code true}, meaning that non-emergency calls
+ * are allowed in emergency callback mode.
+ * @hide
+ */
+ public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL =
+ "allow_non_emergency_calls_in_ecm_bool";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -513,6 +522,7 @@
sDefaults.putString(KEY_MMS_UA_PROF_TAG_NAME_STRING, "x-wap-profile");
sDefaults.putString(KEY_MMS_UA_PROF_URL_STRING, "");
sDefaults.putString(KEY_MMS_USER_AGENT_STRING, "");
+ sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true);
}
/**
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 6177784..95f676e 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -32,7 +32,7 @@
*/
public class WindowManagerPermissionTests extends TestCase {
IWindowManager mWm;
-
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -51,7 +51,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.resumeKeyDispatching(null);
fail("IWindowManager.resumeKeyDispatching did not throw SecurityException as"
@@ -61,7 +61,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.setEventDispatching(true);
fail("IWindowManager.setEventDispatching did not throw SecurityException as"
@@ -71,7 +71,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.addWindowToken(null, 0);
fail("IWindowManager.addWindowToken did not throw SecurityException as"
@@ -81,7 +81,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.removeWindowToken(null);
fail("IWindowManager.removeWindowToken did not throw SecurityException as"
@@ -91,9 +91,10 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
- mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null);
+ mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null,
+ Configuration.EMPTY);
fail("IWindowManager.addAppToken did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
@@ -101,9 +102,9 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
- mWm.setAppTask(null, 0, null);
+ mWm.setAppTask(null, 0, null, null);
fail("IWindowManager.setAppGroupId did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
@@ -111,7 +112,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.updateOrientationFromAppTokens(new Configuration(), null);
fail("IWindowManager.updateOrientationFromAppTokens did not throw SecurityException as"
@@ -121,7 +122,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.setAppOrientation(null, 0);
mWm.addWindowToken(null, 0);
@@ -132,7 +133,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.setFocusedApp(null, false);
fail("IWindowManager.setFocusedApp did not throw SecurityException as"
@@ -142,7 +143,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.prepareAppTransition(0, false);
fail("IWindowManager.prepareAppTransition did not throw SecurityException as"
@@ -152,7 +153,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.executeAppTransition();
fail("IWindowManager.executeAppTransition did not throw SecurityException as"
@@ -162,7 +163,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.setAppStartingWindow(null, "foo", 0, null, null, 0, 0, 0, 0, null, false);
fail("IWindowManager.setAppStartingWindow did not throw SecurityException as"
@@ -172,7 +173,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.setAppWillBeHidden(null);
fail("IWindowManager.setAppWillBeHidden did not throw SecurityException as"
@@ -182,7 +183,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.setAppVisibility(null, false);
fail("IWindowManager.setAppVisibility did not throw SecurityException as"
@@ -192,7 +193,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.startAppFreezingScreen(null, 0);
fail("IWindowManager.startAppFreezingScreen did not throw SecurityException as"
@@ -202,7 +203,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.stopAppFreezingScreen(null, false);
fail("IWindowManager.stopAppFreezingScreen did not throw SecurityException as"
@@ -212,7 +213,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.removeAppToken(null);
fail("IWindowManager.removeAppToken did not throw SecurityException as"
@@ -236,7 +237,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.reenableKeyguard(token);
fail("IWindowManager.reenableKeyguard did not throw SecurityException as"
@@ -246,7 +247,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.exitKeyguardSecurely(null);
fail("IWindowManager.exitKeyguardSecurely did not throw SecurityException as"
@@ -257,7 +258,7 @@
fail("Unexpected remote exception");
}
}
-
+
@SmallTest
public void testSET_ANIMATION_SCALE() {
try {
@@ -269,7 +270,7 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.setAnimationScales(new float[1]);
fail("IWindowManager.setAnimationScales did not throw SecurityException as"
@@ -280,7 +281,7 @@
fail("Unexpected remote exception");
}
}
-
+
@SmallTest
public void testSET_ORIENTATION() {
try {
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 769e2a1..b701445 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -54,7 +54,6 @@
tests/ResourceFilter_test.cpp \
tests/ResourceTable_test.cpp
-aaptHostLdLibs :=
aaptHostStaticLibs := \
libandroidfw \
libpng \
@@ -68,17 +67,13 @@
aaptCFlags := -DAAPT_VERSION=\"$(BUILD_NUMBER_FROM_FILE)\"
aaptCFlags += -Wall -Werror
-ifeq ($(HOST_OS),linux)
- aaptHostLdLibs += -lrt -ldl -lpthread
-endif
+aaptHostLdLibs_linux := -lrt -ldl -lpthread
# Statically link libz for MinGW (Win SDK under Linux),
# and dynamically link for all others.
-ifneq ($(strip $(USE_MINGW)),)
- aaptHostStaticLibs += libz
-else
- aaptHostLdLibs += -lz
-endif
+aaptHostStaticLibs_windows := libz
+aaptHostLdLibs_linux += -lz
+aaptHostLdLibs_darwin := -lz
# ==========================================================
@@ -87,13 +82,13 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libaapt
-LOCAL_CFLAGS += -Wno-format-y2k -DSTATIC_ANDROIDFW_FOR_TOOLS $(aaptCFlags)
-LOCAL_CPPFLAGS += $(aaptCppFlags)
-ifeq (darwin,$(HOST_OS))
-LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS
-endif
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_CFLAGS := -Wno-format-y2k -DSTATIC_ANDROIDFW_FOR_TOOLS $(aaptCFlags)
+LOCAL_CPPFLAGS := $(aaptCppFlags)
+LOCAL_CFLAGS_darwin := -D_DARWIN_UNLIMITED_STREAMS
LOCAL_SRC_FILES := $(aaptSources)
-LOCAL_STATIC_LIBRARIES += $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES := $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(aaptHostStaticLibs_windows)
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -103,11 +98,14 @@
include $(CLEAR_VARS)
LOCAL_MODULE := aapt
-LOCAL_CFLAGS += $(aaptCFlags)
-LOCAL_CPPFLAGS += $(aaptCppFlags)
-LOCAL_LDLIBS += $(aaptHostLdLibs)
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_CFLAGS := $(aaptCFlags)
+LOCAL_CPPFLAGS := $(aaptCppFlags)
+LOCAL_LDLIBS_darwin := $(aaptHostLdLibs_darwin)
+LOCAL_LDLIBS_linux := $(aaptHostLdLibs_linux)
LOCAL_SRC_FILES := $(aaptMain)
-LOCAL_STATIC_LIBRARIES += libaapt $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES := libaapt $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(aaptHostStaticLibs_windows)
include $(BUILD_HOST_EXECUTABLE)
@@ -116,15 +114,16 @@
# Build the host tests: libaapt_tests
# ==========================================================
include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE := libaapt_tests
-LOCAL_CFLAGS += $(aaptCFlags)
-LOCAL_CPPFLAGS += $(aaptCppFlags)
-LOCAL_LDLIBS += $(aaptHostLdLibs)
-LOCAL_SRC_FILES += $(aaptTests)
-LOCAL_C_INCLUDES += $(LOCAL_PATH)
-LOCAL_STATIC_LIBRARIES += libaapt $(aaptHostStaticLibs)
+LOCAL_CFLAGS := $(aaptCFlags)
+LOCAL_CPPFLAGS := $(aaptCppFlags)
+LOCAL_LDLIBS_darwin := $(aaptHostLdLibs_darwin)
+LOCAL_LDLIBS_linux := $(aaptHostLdLibs_linux)
+LOCAL_SRC_FILES := $(aaptTests)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+LOCAL_STATIC_LIBRARIES := libaapt $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(aaptHostStaticLibs_windows)
include $(BUILD_HOST_NATIVE_TEST)
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
index ead5e7a..d7bfccb 100644
--- a/tools/aidl/AST.h
+++ b/tools/aidl/AST.h
@@ -1,5 +1,5 @@
-#ifndef AIDL_AST_H
-#define AIDL_AST_H
+#ifndef AIDL_AST_H_
+#define AIDL_AST_H_
#include <string>
#include <vector>
@@ -368,4 +368,4 @@
virtual void Write(FILE* to);
};
-#endif // AIDL_AST_H
+#endif // AIDL_AST_H_
diff --git a/tools/aidl/Android.mk b/tools/aidl/Android.mk
index efd60a2..354563a 100644
--- a/tools/aidl/Android.mk
+++ b/tools/aidl/Android.mk
@@ -6,24 +6,65 @@
ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),)
LOCAL_PATH:= $(call my-dir)
+
+# Logic shared between aidl and its unittests
include $(CLEAR_VARS)
+LOCAL_MODULE := libaidl-common
+
+LOCAL_CLANG_CFLAGS := -Wall -Werror
+# Tragically, the code is riddled with unused parameters.
+LOCAL_CLANG_CFLAGS += -Wno-unused-parameter
+# yacc dumps a lot of code *just in case*.
+LOCAL_CLANG_CFLAGS += -Wno-unused-function
+LOCAL_CLANG_CFLAGS += -Wno-unneeded-internal-declaration
+# yacc is a tool from a more civilized age.
+LOCAL_CLANG_CFLAGS += -Wno-deprecated-register
+# yacc also has a habit of using char* over const char*.
+LOCAL_CLANG_CFLAGS += -Wno-writable-strings
LOCAL_SRC_FILES := \
- aidl_language_l.l \
- aidl_language_y.y \
- aidl.cpp \
- aidl_language.cpp \
- options.cpp \
- search_path.cpp \
- AST.cpp \
- Type.cpp \
- generate_java.cpp \
- generate_java_binder.cpp \
- generate_java_rpc.cpp
+ AST.cpp \
+ Type.cpp \
+ aidl.cpp \
+ aidl_language.cpp \
+ aidl_language_l.l \
+ aidl_language_y.y \
+ generate_java.cpp \
+ generate_java_binder.cpp \
+ generate_java_rpc.cpp \
+ options.cpp \
+ search_path.cpp \
-LOCAL_CFLAGS := -g
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+# aidl executable
+include $(CLEAR_VARS)
LOCAL_MODULE := aidl
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_SRC_FILES := main.cpp
+LOCAL_STATIC_LIBRARIES := libaidl-common
include $(BUILD_HOST_EXECUTABLE)
+
+# Unit tests
+include $(CLEAR_VARS)
+LOCAL_MODULE := aidl_unittests
+
+LOCAL_CFLAGS := -g -DUNIT_TEST -Wall -Werror
+LOCAL_SRC_FILES := \
+ options_unittest.cpp \
+ test_main.cpp \
+ tests/test.cpp \
+
+LOCAL_STATIC_LIBRARIES := \
+ libaidl-common \
+ libgmock_host \
+ libgtest_host \
+
+LOCAL_LDLIBS := -lrt
+include $(BUILD_HOST_NATIVE_TEST)
+
endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
index ae12720..d799fca 100644
--- a/tools/aidl/Type.h
+++ b/tools/aidl/Type.h
@@ -1,5 +1,5 @@
-#ifndef AIDL_TYPE_H
-#define AIDL_TYPE_H
+#ifndef AIDL_TYPE_H_
+#define AIDL_TYPE_H_
#include "AST.h"
#include <string>
@@ -539,4 +539,4 @@
void register_base_types();
-#endif // AIDL_TYPE_H
+#endif // AIDL_TYPE_H_
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index 438007f..a4ecb75 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -162,11 +162,6 @@
{
}
-static ParserCallbacks g_importCallbacks = {
- &main_document_parsed,
- &import_import_parsed
-};
-
// ==========================================================
static int
check_filename(const char* filename, const char* package, buffer_type* name)
@@ -938,7 +933,7 @@
}
// ==========================================================
-static int
+int
compile_aidl(Options& options)
{
int err = 0, N;
@@ -1068,7 +1063,7 @@
return err;
}
-static int
+int
preprocess_aidl(const Options& options)
{
vector<string> lines;
@@ -1140,24 +1135,3 @@
close(fd);
return 0;
}
-
-// ==========================================================
-int
-main(int argc, const char **argv)
-{
- Options options;
- int result = parse_options(argc, argv, &options);
- if (result) {
- return result;
- }
-
- switch (options.task)
- {
- case COMPILE_AIDL:
- return compile_aidl(options);
- case PREPROCESS_AIDL:
- return preprocess_aidl(options);
- }
- fprintf(stderr, "aidl: internal error\n");
- return 1;
-}
diff --git a/tools/aidl/aidl.h b/tools/aidl/aidl.h
new file mode 100644
index 0000000..98b15f3
--- /dev/null
+++ b/tools/aidl/aidl.h
@@ -0,0 +1,9 @@
+#ifndef AIDL_AIDL_H_
+#define AIDL_AIDL_H_
+
+#include "options.h"
+
+int compile_aidl(Options& options);
+int preprocess_aidl(const Options& options);
+
+#endif // AIDL_AIDL_H_
diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h
index de1370c..1be5a9b 100644
--- a/tools/aidl/aidl_language.h
+++ b/tools/aidl/aidl_language.h
@@ -1,5 +1,5 @@
-#ifndef DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
-#define DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
+#ifndef AIDL_AIDL_LANGUAGE_H_
+#define AIDL_AIDL_LANGUAGE_H_
typedef enum {
@@ -169,4 +169,4 @@
#endif
-#endif // DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
+#endif // AIDL_AIDL_LANGUAGE_H_
diff --git a/tools/aidl/generate_java.h b/tools/aidl/generate_java.h
index 4bfcfeb..ae7983f 100644
--- a/tools/aidl/generate_java.h
+++ b/tools/aidl/generate_java.h
@@ -1,5 +1,5 @@
-#ifndef GENERATE_JAVA_H
-#define GENERATE_JAVA_H
+#ifndef AIDL_GENERATE_JAVA_H_
+#define AIDL_GENERATE_JAVA_H_
#include "aidl_language.h"
#include "AST.h"
@@ -29,5 +29,5 @@
int m_index;
};
-#endif // GENERATE_JAVA_H
+#endif // AIDL_GENERATE_JAVA_H_
diff --git a/tools/aidl/main.cpp b/tools/aidl/main.cpp
new file mode 100644
index 0000000..7cc2198
--- /dev/null
+++ b/tools/aidl/main.cpp
@@ -0,0 +1,23 @@
+#include "aidl.h"
+#include "options.h"
+
+#include <stdio.h>
+
+int
+main(int argc, const char **argv)
+{
+ Options options;
+ int result = parse_options(argc, argv, &options);
+ if (result) {
+ return result;
+ }
+
+ switch (options.task) {
+ case COMPILE_AIDL:
+ return compile_aidl(options);
+ case PREPROCESS_AIDL:
+ return preprocess_aidl(options);
+ }
+ fprintf(stderr, "aidl: internal error\n");
+ return 1;
+}
diff --git a/tools/aidl/options.cpp b/tools/aidl/options.cpp
index 7b2daeb..52b0972 100644
--- a/tools/aidl/options.cpp
+++ b/tools/aidl/options.cpp
@@ -48,10 +48,6 @@
return 0;
}
- options->task = COMPILE_AIDL;
- options->failOnParcelable = false;
- options->autoDepFile = false;
-
// OPTIONS
while (i < argc) {
const char* s = argv[i];
diff --git a/tools/aidl/options.h b/tools/aidl/options.h
index 387e37d..4e95e11 100644
--- a/tools/aidl/options.h
+++ b/tools/aidl/options.h
@@ -1,5 +1,5 @@
-#ifndef DEVICE_TOOLS_AIDL_H
-#define DEVICE_TOOLS_AIDL_H
+#ifndef AIDL_OPTIONS_H_
+#define AIDL_OPTIONS_H_
#include <string.h>
#include <string>
@@ -15,15 +15,15 @@
// This struct is the parsed version of the command line options
struct Options
{
- int task;
- bool failOnParcelable;
+ int task{COMPILE_AIDL};
+ bool failOnParcelable{false};
vector<string> importPaths;
vector<string> preprocessedFiles;
string inputFileName;
string outputFileName;
string outputBaseFolder;
string depFileName;
- bool autoDepFile;
+ bool autoDepFile{false};
vector<string> filesToPreprocess;
};
@@ -33,4 +33,4 @@
// It also prints the usage statement on failure.
int parse_options(int argc, const char* const* argv, Options *options);
-#endif // DEVICE_TOOLS_AIDL_H
+#endif // AIDL_OPTIONS_H_
diff --git a/tools/aidl/options_unittest.cpp b/tools/aidl/options_unittest.cpp
new file mode 100644
index 0000000..fec7f87
--- /dev/null
+++ b/tools/aidl/options_unittest.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "options.h"
+
+using std::vector;
+using std::string;
+
+const char kPreprocessCommandOutputFile[] = "output_file_name";
+const char kPreprocessCommandInput1[] = "input1";
+const char kPreprocessCommandInput2[] = "input2";
+const char kPreprocessCommandInput3[] = "input3";
+const char* kPreprocessCommand[] = {
+ "aidl", "--preprocess",
+ kPreprocessCommandOutputFile,
+ kPreprocessCommandInput1,
+ kPreprocessCommandInput2,
+ kPreprocessCommandInput3,
+};
+
+TEST(OptionsTests, ParsesPreprocess) {
+ Options options;
+ const int argc = sizeof(kPreprocessCommand) / sizeof(*kPreprocessCommand);
+ EXPECT_EQ(parse_options(argc, kPreprocessCommand, &options), 0);
+ EXPECT_EQ(options.task, PREPROCESS_AIDL);
+ EXPECT_EQ(options.failOnParcelable, false);
+ EXPECT_EQ(options.importPaths.size(), 0u);
+ EXPECT_EQ(options.preprocessedFiles.size(), 0u);
+ EXPECT_EQ(options.inputFileName, string{""});
+ EXPECT_EQ(options.outputFileName, string{kPreprocessCommandOutputFile});
+ EXPECT_EQ(options.autoDepFile, false);
+ const vector<string> expected_input{kPreprocessCommandInput1,
+ kPreprocessCommandInput2,
+ kPreprocessCommandInput3};
+ EXPECT_EQ(options.filesToPreprocess, expected_input);
+}
diff --git a/tools/aidl/os.h b/tools/aidl/os.h
index 79d2c35..752ed47 100644
--- a/tools/aidl/os.h
+++ b/tools/aidl/os.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef _FRAMEWORKS_BASE_TOOLS_AIDL_OS_SEP_H_
-#define _FRAMEWORKS_BASE_TOOLS_AIDL_OS_SEP_H_
+#ifndef AIDL_OS_H_
+#define AIDL_OS_H_
#if defined(_WIN32)
#define OS_PATH_SEPARATOR '\\'
@@ -23,4 +23,4 @@
#define OS_PATH_SEPARATOR '/'
#endif
-#endif
+#endif // AIDL_OS_H_
diff --git a/tools/aidl/search_path.h b/tools/aidl/search_path.h
index 2bf94b1..4fec257 100644
--- a/tools/aidl/search_path.h
+++ b/tools/aidl/search_path.h
@@ -1,5 +1,5 @@
-#ifndef DEVICE_TOOLS_AIDL_SEARCH_PATH_H
-#define DEVICE_TOOLS_AIDL_SEARCH_PATH_H
+#ifndef AIDL_SEARCH_PATH_H_
+#define AIDL_SEARCH_PATH_H_
#include <stdio.h>
@@ -19,5 +19,4 @@
void set_import_paths(const vector<string>& importPaths);
#endif
-#endif // DEVICE_TOOLS_AIDL_SEARCH_PATH_H
-
+#endif // AIDL_SEARCH_PATH_H_
diff --git a/tools/aidl/test_main.cpp b/tools/aidl/test_main.cpp
new file mode 100644
index 0000000..4d820af7
--- /dev/null
+++ b/tools/aidl/test_main.cpp
@@ -0,0 +1,6 @@
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/tools/aidl/tests/test.cpp b/tools/aidl/tests/test.cpp
new file mode 100644
index 0000000..15ae294
--- /dev/null
+++ b/tools/aidl/tests/test.cpp
@@ -0,0 +1,3 @@
+#include <gtest/gtest.h>
+
+TEST(DummyCase, DummyTest) {}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index a8fd91c..ed8b56e 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -74,11 +74,10 @@
// ---- unused implementation of IWindowManager ----
@Override
- public Configuration addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
+ public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9, boolean arg10,
- Rect arg11) throws RemoteException {
+ Rect arg11, Configuration arg12) throws RemoteException {
// TODO Auto-generated method stub
- return Configuration.EMPTY;
}
@Override
@@ -315,9 +314,9 @@
}
@Override
- public Configuration setAppTask(IBinder arg0, int arg1, Rect arg2) throws RemoteException {
+ public void setAppTask(IBinder arg0, int arg1, Rect arg2, Configuration arg3)
+ throws RemoteException {
// TODO Auto-generated method stub
- return Configuration.EMPTY;
}
@Override
diff --git a/tools/split-select/Android.mk b/tools/split-select/Android.mk
index d9ddf08..239bed5 100644
--- a/tools/split-select/Android.mk
+++ b/tools/split-select/Android.mk
@@ -43,7 +43,6 @@
external/zlib \
frameworks/base/tools
-hostLdLibs :=
hostStaticLibs := \
libaapt \
libandroidfw \
@@ -57,17 +56,13 @@
cFlags := -Wall -Werror
-ifeq ($(HOST_OS),linux)
- hostLdLibs += -lrt -ldl -lpthread
-endif
+hostLdLibs_linux := -lrt -ldl -lpthread
# Statically link libz for MinGW (Win SDK under Linux),
# and dynamically link for all others.
-ifneq ($(strip $(USE_MINGW)),)
- hostStaticLibs += libz
-else
- hostLdLibs += -lz
-endif
+hostStaticLibs_windows := libz
+hostLdLibs_darwin := -lz
+hostLdLibs_linux += -lz
# ==========================================================
@@ -75,11 +70,12 @@
# ==========================================================
include $(CLEAR_VARS)
LOCAL_MODULE := libsplit-select
+LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_SRC_FILES := $(sources)
-LOCAL_C_INCLUDES += $(cIncludes)
-LOCAL_CFLAGS += $(cFlags) -D_DARWIN_UNLIMITED_STREAMS
+LOCAL_C_INCLUDES := $(cIncludes)
+LOCAL_CFLAGS := $(cFlags) -D_DARWIN_UNLIMITED_STREAMS
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -93,10 +89,12 @@
LOCAL_SRC_FILES := $(testSources)
-LOCAL_C_INCLUDES += $(cIncludes)
-LOCAL_STATIC_LIBRARIES += libsplit-select $(hostStaticLibs)
-LOCAL_LDLIBS += $(hostLdLibs)
-LOCAL_CFLAGS += $(cFlags)
+LOCAL_C_INCLUDES := $(cIncludes)
+LOCAL_STATIC_LIBRARIES := libsplit-select $(hostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(hostStaticLibs_windows)
+LOCAL_LDLIBS_darwin := $(hostLdLibs_darwin)
+LOCAL_LDLIBS_linux := $(hostLdLibs_linux)
+LOCAL_CFLAGS := $(cFlags)
include $(BUILD_HOST_NATIVE_TEST)
@@ -105,13 +103,16 @@
# ==========================================================
include $(CLEAR_VARS)
LOCAL_MODULE := split-select
+LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_SRC_FILES := $(main)
-LOCAL_C_INCLUDES += $(cIncludes)
-LOCAL_STATIC_LIBRARIES += libsplit-select $(hostStaticLibs)
-LOCAL_LDLIBS += $(hostLdLibs)
-LOCAL_CFLAGS += $(cFlags)
+LOCAL_C_INCLUDES := $(cIncludes)
+LOCAL_STATIC_LIBRARIES := libsplit-select $(hostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(hostStaticLibs_windows)
+LOCAL_LDLIBS_darwin := $(hostLdLibs_darwin)
+LOCAL_LDLIBS_linux := $(hostLdLibs_linux)
+LOCAL_CFLAGS := $(cFlags)
include $(BUILD_HOST_EXECUTABLE)