Merge "Fix the Locale story in the hotword API" into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index 20c4db9..a592b0e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22465,21 +22465,21 @@
}
public final class PowerManager {
- method public void goToSleep(long);
method public boolean isInteractive();
method public boolean isPowerSaveMode();
method public deprecated boolean isScreenOn();
+ method public boolean isWakeLockLevelSupported(int);
method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
method public void reboot(java.lang.String);
- method public void userActivity(long, boolean);
- method public void wakeUp(long);
field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
field public static final java.lang.String ACTION_POWER_SAVE_MODE_CHANGED = "android.os.action.POWER_SAVE_MODE_CHANGED";
field public static final deprecated int FULL_WAKE_LOCK = 26; // 0x1a
field public static final int ON_AFTER_RELEASE = 536870912; // 0x20000000
field public static final int PARTIAL_WAKE_LOCK = 1; // 0x1
+ field public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32; // 0x20
field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
+ field public static final int WAIT_FOR_PROXIMITY_NEGATIVE = 1; // 0x1
}
public final class PowerManager.WakeLock {
@@ -22487,6 +22487,7 @@
method public void acquire(long);
method public boolean isHeld();
method public void release();
+ method public void release(int);
method public void setReferenceCounted(boolean);
method public void setWorkSource(android.os.WorkSource);
}
diff --git a/api/removed.txt b/api/removed.txt
index 465a18d..93484de 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -6,6 +6,16 @@
}
+package android.os {
+
+ public final class PowerManager {
+ method public void goToSleep(long);
+ method public deprecated void userActivity(long, boolean);
+ method public void wakeUp(long);
+ }
+
+}
+
package android.view {
public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 0dc8f66..41bbb87 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1373,6 +1373,8 @@
* and its profiles or a particular one.
* @param admin The name of the admin component to check, or null to aggregate
* all admins.
+ * @return time in milliseconds for the given admin or the minimum value (strictest) of
+ * all admins if admin is null.
*/
public long getMaximumTimeToLock(ComponentName admin) {
return getMaximumTimeToLock(admin, UserHandle.myUserId());
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 75f8279..f7b0ead 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -17,6 +17,7 @@
package android.os;
import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
import android.content.Context;
import android.util.Log;
@@ -186,8 +187,6 @@
* </p><p>
* Cannot be used with {@link #ACQUIRE_CAUSES_WAKEUP}.
* </p>
- *
- * {@hide}
*/
public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020;
@@ -197,6 +196,8 @@
* <p>
* This is used by the dream manager to implement doze mode. It currently
* has no effect unless the power manager is in the dozing state.
+ * </p><p>
+ * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
* </p>
*
* {@hide}
@@ -243,11 +244,9 @@
public static final int UNIMPORTANT_FOR_LOGGING = 0x40000000;
/**
- * Flag for {@link WakeLock#release release(int)} to defer releasing a
- * {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK} wake lock until the proximity sensor returns
- * a negative value.
- *
- * {@hide}
+ * Flag for {@link WakeLock#release WakeLock.release(int)}: Defer releasing a
+ * {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK} wake lock until the proximity sensor
+ * indicates that an object is not in close proximity.
*/
public static final int WAIT_FOR_PROXIMITY_NEGATIVE = 1;
@@ -276,28 +275,44 @@
* User activity event type: Unspecified event type.
* @hide
*/
+ @SystemApi
public static final int USER_ACTIVITY_EVENT_OTHER = 0;
/**
* User activity event type: Button or key pressed or released.
* @hide
*/
+ @SystemApi
public static final int USER_ACTIVITY_EVENT_BUTTON = 1;
/**
* User activity event type: Touch down, move or up.
* @hide
*/
+ @SystemApi
public static final int USER_ACTIVITY_EVENT_TOUCH = 2;
/**
- * User activity flag: Do not restart the user activity timeout or brighten
- * the display in response to user activity if it is already dimmed.
+ * User activity flag: If already dimmed, extend the dim timeout
+ * but do not brighten. This flag is useful for keeping the screen on
+ * a little longer without causing a visible change such as when
+ * the power key is pressed.
* @hide
*/
+ @SystemApi
public static final int USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS = 1 << 0;
/**
+ * User activity flag: Note the user activity as usual but do not
+ * reset the user activity timeout. This flag is useful for applying
+ * user activity power hints when interacting with the device indirectly
+ * on a secondary screen while allowing the primary screen to go to sleep.
+ * @hide
+ */
+ @SystemApi
+ public static final int USER_ACTIVITY_FLAG_INDIRECT = 1 << 1;
+
+ /**
* Go to sleep reason code: Going to sleep due by application request.
* @hide
*/
@@ -335,6 +350,12 @@
public static final int GO_TO_SLEEP_REASON_HDMI = 5;
/**
+ * Go to sleep flag: Skip dozing state and directly go to full sleep.
+ * @hide
+ */
+ public static final int GO_TO_SLEEP_FLAG_NO_DOZE = 1 << 0;
+
+ /**
* The value to pass as the 'reason' argument to reboot() to
* reboot into recovery mode (for applying system updates, doing
* factory resets, etc.).
@@ -347,12 +368,6 @@
*/
public static final String REBOOT_RECOVERY = "recovery";
- /**
- * Go to sleep flag: Skip dozing state and directly go to full sleep.
- * @hide
- */
- public static final int GO_TO_SLEEP_FLAG_NO_DOZE = 1 << 0;
-
final Context mContext;
final IPowerManager mService;
final Handler mHandler;
@@ -456,6 +471,7 @@
* @see #FULL_WAKE_LOCK
* @see #SCREEN_DIM_WAKE_LOCK
* @see #SCREEN_BRIGHT_WAKE_LOCK
+ * @see #PROXIMITY_SCREEN_OFF_WAKE_LOCK
* @see #ACQUIRE_CAUSES_WAKEUP
* @see #ON_AFTER_RELEASE
*/
@@ -505,11 +521,44 @@
*
* @see #wakeUp
* @see #goToSleep
+ *
+ * @removed Requires signature or system permission.
+ * @deprecated Use {@link #userActivity(long, int, int)}.
*/
+ @Deprecated
public void userActivity(long when, boolean noChangeLights) {
+ userActivity(when, USER_ACTIVITY_EVENT_OTHER,
+ noChangeLights ? USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS : 0);
+ }
+
+ /**
+ * Notifies the power manager that user activity happened.
+ * <p>
+ * Resets the auto-off timer and brightens the screen if the device
+ * is not asleep. This is what happens normally when a key or the touch
+ * screen is pressed or when some other user activity occurs.
+ * This method does not wake up the device if it has been put to sleep.
+ * </p><p>
+ * Requires the {@link android.Manifest.permission#DEVICE_POWER} or
+ * {@link android.Manifest.permission#USER_ACTIVITY} permission.
+ * </p>
+ *
+ * @param when The time of the user activity, in the {@link SystemClock#uptimeMillis()}
+ * time base. This timestamp is used to correctly order the user activity request with
+ * other power management functions. It should be set
+ * to the timestamp of the input event that caused the user activity.
+ * @param event The user activity event.
+ * @param flags Optional user activity flags.
+ *
+ * @see #wakeUp
+ * @see #goToSleep
+ *
+ * @hide Requires signature or system permission.
+ */
+ @SystemApi
+ public void userActivity(long when, int event, int flags) {
try {
- mService.userActivity(when, USER_ACTIVITY_EVENT_OTHER,
- noChangeLights ? USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS : 0);
+ mService.userActivity(when, event, flags);
} catch (RemoteException e) {
}
}
@@ -530,13 +579,33 @@
*
* @see #userActivity
* @see #wakeUp
+ *
+ * @removed Requires signature permission.
*/
public void goToSleep(long time) {
goToSleep(time, GO_TO_SLEEP_REASON_APPLICATION, 0);
}
/**
- * @hide
+ * Forces the device to go to sleep.
+ * <p>
+ * Overrides all the wake locks that are held.
+ * This is what happens when the power key is pressed to turn off the screen.
+ * </p><p>
+ * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
+ * </p>
+ *
+ * @param time The time when the request to go to sleep was issued, in the
+ * {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly
+ * order the go to sleep request with other power management functions. It should be set
+ * to the timestamp of the input event that caused the request to go to sleep.
+ * @param reason The reason the device is going to sleep.
+ * @param flags Optional flags to apply when going to sleep.
+ *
+ * @see #userActivity
+ * @see #wakeUp
+ *
+ * @hide Requires signature permission.
*/
public void goToSleep(long time, int reason, int flags) {
try {
@@ -561,6 +630,8 @@
*
* @see #userActivity
* @see #goToSleep
+ *
+ * @removed Requires signature permission.
*/
public void wakeUp(long time) {
try {
@@ -588,7 +659,7 @@
* @see #wakeUp
* @see #goToSleep
*
- * @hide
+ * @hide Requires signature permission.
*/
public void nap(long time) {
try {
@@ -605,7 +676,7 @@
*
* @param brightness The brightness value from 0 to 255.
*
- * {@hide}
+ * @hide Requires signature permission.
*/
public void setBacklightBrightness(int brightness) {
try {
@@ -619,8 +690,6 @@
*
* @param level The wake lock level to check.
* @return True if the specified wake lock level is supported.
- *
- * {@hide}
*/
public boolean isWakeLockLevelSupported(int level) {
try {
@@ -893,8 +962,6 @@
*
* @param flags Combination of flag values to modify the release behavior.
* Currently only {@link #WAIT_FOR_PROXIMITY_NEGATIVE} is supported.
- *
- * {@hide}
*/
public void release(int flags) {
synchronized (mToken) {
diff --git a/core/java/android/service/trust/ITrustAgentService.aidl b/core/java/android/service/trust/ITrustAgentService.aidl
index 637d080..bd80a3f 100644
--- a/core/java/android/service/trust/ITrustAgentService.aidl
+++ b/core/java/android/service/trust/ITrustAgentService.aidl
@@ -24,6 +24,7 @@
*/
interface ITrustAgentService {
oneway void onUnlockAttempt(boolean successful);
+ oneway void onTrustTimeout();
oneway void setCallback(ITrustAgentServiceCallback callback);
oneway void setTrustAgentFeaturesEnabled(in Bundle options, IBinder token);
}
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 5fe9194..337ae60 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -30,6 +30,7 @@
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.util.Log;
import android.util.Slog;
@@ -37,7 +38,10 @@
* A service that notifies the system about whether it believes the environment of the device
* to be trusted.
*
- * <p>Trust agents may only be provided by the platform.</p>
+ * <p>Trust agents may only be provided by the platform. It is expected that there is only
+ * one trust agent installed on the platform. In the event there is more than one,
+ * either trust agent can enable trust.
+ * </p>
*
* <p>To extend this class, you must declare the service in your manifest file with
* the {@link android.Manifest.permission#BIND_TRUST_AGENT} permission
@@ -90,6 +94,7 @@
private static final int MSG_UNLOCK_ATTEMPT = 1;
private static final int MSG_SET_TRUST_AGENT_FEATURES_ENABLED = 2;
+ private static final int MSG_TRUST_TIMEOUT = 3;
private ITrustAgentServiceCallback mCallback;
@@ -118,6 +123,9 @@
onError("calling onSetTrustAgentFeaturesEnabledCompleted()");
}
break;
+ case MSG_TRUST_TIMEOUT:
+ onTrustTimeout();
+ break;
}
}
};
@@ -139,21 +147,32 @@
}
/**
- * Called when the user attempted to authenticate on the device.
+ * Called after the user attempts to authenticate in keyguard with their device credentials,
+ * such as pin, pattern or password.
*
- * @param successful true if the attempt succeeded
+ * @param successful true if the user successfully completed the challenge.
*/
public void onUnlockAttempt(boolean successful) {
}
+ /**
+ * Called when the timeout provided by the agent expires. Note that this may be called earlier
+ * than requested by the agent if the trust timeout is adjusted by the system or
+ * {@link DevicePolicyManager}. The agent is expected to re-evaluate the trust state and only
+ * call {@link #grantTrust(CharSequence, long, boolean)} if the trust state should be
+ * continued.
+ */
+ public void onTrustTimeout() {
+ }
+
private void onError(String msg) {
Slog.v(TAG, "Remote exception while " + msg);
}
/**
- * Called when device policy wants to restrict features in the TrustAgent in response to
+ * Called when device policy wants to restrict features in the agent in response to
* {@link DevicePolicyManager#setTrustAgentFeaturesEnabled(ComponentName, ComponentName, java.util.List) }.
- * TrustAgents that support this feature should overload this method and return 'true'.
+ * Agents that support this feature should overload this method and return 'true'.
*
* The list of options can be obtained by calling
* options.getStringArrayList({@link #KEY_FEATURES}). Presence of a feature string in the list
@@ -174,10 +193,19 @@
* Call to grant trust on the device.
*
* @param message describes why the device is trusted, e.g. "Trusted by location".
- * @param durationMs amount of time in milliseconds to keep the device in a trusted state. Trust
- * for this agent will automatically be revoked when the timeout expires.
- * @param initiatedByUser indicates that the user has explicitly initiated an action that proves
- * the user is about to use the device.
+ * @param durationMs amount of time in milliseconds to keep the device in a trusted state.
+ * Trust for this agent will automatically be revoked when the timeout expires unless
+ * extended by a subsequent call to this function. The timeout is measured from the
+ * invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}.
+ * For security reasons, the value should be no larger than necessary.
+ * The value may be adjusted by the system as necessary to comply with a policy controlled
+ * by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()}
+ * for determining when trust expires.
+ * @param initiatedByUser this is a hint to the system that trust is being granted as the
+ * direct result of user action - such as solving a security challenge. The hint is used
+ * by the system to optimize the experience. Behavior may vary by device and release, so
+ * one should only set this parameter if it meets the above criteria rather than relying on
+ * the behavior of any particular device or release.
* @throws IllegalStateException if the agent is not currently managing trust.
*/
public final void grantTrust(
@@ -254,13 +282,17 @@
}
private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub {
- @Override
+ @Override /* Binder API */
public void onUnlockAttempt(boolean successful) {
- mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0)
- .sendToTarget();
+ mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0).sendToTarget();
}
- @Override
+ @Override /* Binder API */
+ public void onTrustTimeout() {
+ mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
+ }
+
+ @Override /* Binder API */
public void setCallback(ITrustAgentServiceCallback callback) {
synchronized (mLock) {
mCallback = callback;
@@ -280,7 +312,7 @@
}
}
- @Override
+ @Override /* Binder API */
public void setTrustAgentFeaturesEnabled(Bundle features, IBinder token) {
Message msg = mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_ENABLED, token);
msg.setData(features);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 096fe88..9b3a1e0 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5719,8 +5719,6 @@
}
if (mEditor != null && mEditor.mKeyListener != null) {
- resetErrorChangedFlag();
-
boolean doDown = true;
if (otherEvent != null) {
try {
@@ -7637,6 +7635,7 @@
list.get(i).afterTextChanged(text);
}
}
+ hideErrorIfUnchanged();
}
void updateAfterEdit() {
@@ -7676,7 +7675,7 @@
}
ims.mChangedDelta += after-before;
}
-
+ resetErrorChangedFlag();
sendOnTextChanged(buffer, start, before, after);
onTextChanged(buffer, start, before, after);
}
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 1b89179..ae44047 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -37,6 +37,8 @@
import java.util.Calendar;
import java.util.Locale;
+import libcore.icu.LocaleData;
+
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
@@ -143,11 +145,8 @@
mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
- /* Get the localized am/pm strings and use them in the spinner */
- final Resources res = context.getResources();
- final String amText = res.getString(R.string.time_picker_am_label);
- final String pmText = res.getString(R.string.time_picker_pm_label);
- mAmPmStrings = new String[] {amText, pmText};
+ // Get the localized am/pm strings and use them in the spinner.
+ mAmPmStrings = getAmPmStrings(context);
// am/pm
View amPmView = mDelegator.findViewById(R.id.amPm);
@@ -601,5 +600,12 @@
}
};
}
-}
+ public static String[] getAmPmStrings(Context context) {
+ String[] result = new String[2];
+ LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
+ result[0] = d.amPm[0].length() > 2 ? d.narrowAm : d.amPm[0];
+ result[1] = d.amPm[1].length() > 2 ? d.narrowPm : d.amPm[1];
+ return result;
+ }
+}
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 9a50250..dd1bf4f 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -127,8 +127,10 @@
mSelectHours = res.getString(R.string.select_hours);
mMinutePickerDescription = res.getString(R.string.minute_picker_description);
mSelectMinutes = res.getString(R.string.select_minutes);
- mAmText = res.getString(R.string.time_picker_am_label);
- mPmText = res.getString(R.string.time_picker_pm_label);
+
+ String[] amPmStrings = TimePickerClockDelegate.getAmPmStrings(context);
+ mAmText = amPmStrings[0];
+ mPmText = amPmStrings[1];
final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
R.layout.time_picker_holo);
diff --git a/core/java/com/android/internal/net/LegacyVpnInfo.java b/core/java/com/android/internal/net/LegacyVpnInfo.java
index f812ad6..d6f6d0b 100644
--- a/core/java/com/android/internal/net/LegacyVpnInfo.java
+++ b/core/java/com/android/internal/net/LegacyVpnInfo.java
@@ -40,6 +40,7 @@
public String key;
public int state = -1;
+ public PendingIntent intent;
@Override
public int describeContents() {
@@ -50,6 +51,7 @@
public void writeToParcel(Parcel out, int flags) {
out.writeString(key);
out.writeInt(state);
+ out.writeParcelable(intent, flags);
}
public static final Parcelable.Creator<LegacyVpnInfo> CREATOR =
@@ -59,6 +61,7 @@
LegacyVpnInfo info = new LegacyVpnInfo();
info.key = in.readString();
info.state = in.readInt();
+ info.intent = in.readParcelable(null);
return info;
}
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index aa66d7d..9c3f419 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -28,6 +28,7 @@
import android.net.RouteInfo;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import java.net.Inet4Address;
import java.net.InetAddress;
@@ -57,6 +58,15 @@
return intent;
}
+ /** NOTE: This should only be used for legacy VPN. */
+ public static PendingIntent getIntentForStatusPanel(Context context) {
+ Intent intent = new Intent();
+ intent.setClassName(DIALOGS_PACKAGE, DIALOGS_PACKAGE + ".ManageDialog");
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY |
+ Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ return PendingIntent.getActivityAsUser(context, 0, intent, 0, null, UserHandle.CURRENT);
+ }
+
public static CharSequence getVpnLabel(Context context, String packageName)
throws NameNotFoundException {
PackageManager pm = context.getPackageManager();
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0a395e1..672ad84 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2408,6 +2408,13 @@
android:description="@string/permdesc_devicePower"
android:protectionLevel="signature" />
+ <!-- Allows access to the PowerManager.userActivity function.
+ <p>Not for use by third-party applications. @hide @SystemApi -->
+ <permission android:name="android.permission.USER_ACTIVITY"
+ android:label="@string/permlab_userActivity"
+ android:description="@string/permdesc_userActivity"
+ android:protectionLevel="signature|system" />
+
<!-- @hide Allows low-level access to tun tap driver -->
<permission android:name="android.permission.NET_TUNNELING"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
diff --git a/core/res/res/values-television/styles.xml b/core/res/res/values-television/styles.xml
new file mode 100644
index 0000000..4c0562f
--- /dev/null
+++ b/core/res/res/values-television/styles.xml
@@ -0,0 +1,22 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <style name="Lighting">
+ <item name="lightY">-300dp</item>
+ <item name="ambientShadowAlpha">0.4</item>
+ <item name="spotShadowAlpha">0.4</item>
+ </style>
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c6478ab..4f0757c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -673,6 +673,37 @@
-->
<integer name="config_doubleTapOnHomeBehavior">0</integer>
+ <!-- Minimum screen brightness setting allowed by the power manager.
+ The user is forbidden from setting the brightness below this level. -->
+ <integer name="config_screenBrightnessSettingMinimum">10</integer>
+
+ <!-- Maximum screen brightness allowed by the power manager.
+ The user is forbidden from setting the brightness above this level. -->
+ <integer name="config_screenBrightnessSettingMaximum">255</integer>
+
+ <!-- Default screen brightness setting.
+ Must be in the range specified by minimum and maximum. -->
+ <integer name="config_screenBrightnessSettingDefault">102</integer>
+
+ <!-- Screen brightness used to dim the screen while dozing in a very low power state.
+ May be less than the minimum allowed brightness setting
+ that can be set by the user. -->
+ <integer name="config_screenBrightnessDoze">1</integer>
+
+ <!-- Screen brightness used to dim the screen when the user activity
+ timeout expires. May be less than the minimum allowed brightness setting
+ that can be set by the user. -->
+ <integer name="config_screenBrightnessDim">10</integer>
+
+ <!-- Minimum allowable screen brightness to use in a very dark room.
+ This value sets the floor for the darkest possible auto-brightness
+ adjustment. It is expected to be somewhat less than the first entry in
+ config_autoBrightnessLcdBacklightValues so as to allow the user to have
+ some range of adjustment to dim the screen further than usual in very
+ dark rooms. The contents of the screen must still be clearly visible
+ in darkness (although they may not be visible in a bright room). -->
+ <integer name="config_screenBrightnessDark">1</integer>
+
<!-- Array of light sensor LUX values to define our levels for auto backlight brightness support.
The N entries of this array define N + 1 control points as follows:
(1-based arrays)
@@ -696,28 +727,6 @@
<integer-array name="config_autoBrightnessLevels">
</integer-array>
- <!-- Minimum screen brightness setting allowed by the power manager.
- The user is forbidden from setting the brightness below this level. -->
- <integer name="config_screenBrightnessSettingMinimum">10</integer>
-
- <!-- Maximum screen brightness allowed by the power manager.
- The user is forbidden from setting the brightness above this level. -->
- <integer name="config_screenBrightnessSettingMaximum">255</integer>
-
- <!-- Default screen brightness setting.
- Must be in the range specified by minimum and maximum. -->
- <integer name="config_screenBrightnessSettingDefault">102</integer>
-
- <!-- Screen brightness used to dim the screen while dozing in a very low power state.
- May be less than the minimum allowed brightness setting
- that can be set by the user. -->
- <integer name="config_screenBrightnessDoze">1</integer>
-
- <!-- Screen brightness used to dim the screen when the user activity
- timeout expires. May be less than the minimum allowed brightness setting
- that can be set by the user. -->
- <integer name="config_screenBrightnessDim">10</integer>
-
<!-- Array of output values for LCD backlight corresponding to the LUX values
in the config_autoBrightnessLevels array. This array should have size one greater
than the size of the config_autoBrightnessLevels array.
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1453e15..b167c0a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1815,6 +1815,11 @@
<string name="permdesc_devicePower" product="default">Allows the app to turn the phone on or off.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_userActivity">reset display timeout</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_userActivity">Allows the app to reset the display timeout.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_factoryTest">run in factory test mode</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_factoryTest" product="tablet">Run as a low-level manufacturer test,
@@ -4142,10 +4147,6 @@
<string name="time_picker_increment_set_pm_button">Set PM</string>
<!-- Description of the button to decrease the TimePicker's set AM value. [CHAR LIMIT=NONE] -->
<string name="time_picker_decrement_set_am_button">Set AM</string>
- <!-- Label for the TimePicker's PM button. [CHAR LIMIT=2] -->
- <string name="time_picker_pm_label">PM</string>
- <!-- Label for the TimePicker's AM button. [CHAR LIMIT=2] -->
- <string name="time_picker_am_label">AM</string>
<!-- DatePicker - accessibility support -->
<!-- Description of the button to increase the DatePicker's month value. [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b5ec56a..3f373aa 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1565,6 +1565,7 @@
<java-symbol type="integer" name="config_screenBrightnessSettingMinimum" />
<java-symbol type="integer" name="config_screenBrightnessSettingMaximum" />
<java-symbol type="integer" name="config_screenBrightnessSettingDefault" />
+ <java-symbol type="integer" name="config_screenBrightnessDark" />
<java-symbol type="integer" name="config_screenBrightnessDim" />
<java-symbol type="integer" name="config_screenBrightnessDoze" />
<java-symbol type="integer" name="config_shutdownBatteryTemperature" />
@@ -1985,8 +1986,6 @@
<java-symbol type="attr" name="headerSelectedTextColor" />
<java-symbol type="attr" name="amPmSelectedBackgroundColor" />
<java-symbol type="bool" name="config_sms_decode_gsm_8bit_data" />
- <java-symbol type="string" name="time_picker_am_label" />
- <java-symbol type="string" name="time_picker_pm_label" />
<java-symbol type="dimen" name="text_size_small_material" />
<java-symbol type="attr" name="checkMarkGravity" />
<java-symbol type="layout" name="select_dialog_singlechoice_material" />
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index b4b0e53..01995c7 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -127,10 +127,11 @@
assertTrue("failed to connect to " + mTestAccessPoint,
connectToWifi(mTestAccessPoint));
// assert that WifiManager reports correct state
- assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
+ assertTrue("wifi not enabled", waitForWifiState(
+ WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
// assert that ConnectivityManager reports correct state for Wifi
- assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- WIFI_CONNECTION_TIMEOUT));
+ assertTrue("wifi not connected", waitForNetworkState(
+ ConnectivityManager.TYPE_WIFI, State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
// below check disbabled since we have bug in what ConnectivityManager returns
// if (!mWifiOnlyFlag) {
// // assert that ConnectivityManager reports correct state for mobile
@@ -267,8 +268,8 @@
// connect to Wifi
assertTrue("failed to connect to " + mTestAccessPoint,
connectToWifi(mTestAccessPoint));
- assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- WIFI_CONNECTION_TIMEOUT));
+ assertTrue("wifi not connected", waitForNetworkState(
+ ConnectivityManager.TYPE_WIFI, State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
// verify that connection actually works
assertTrue("no network connectivity after wifi enable", checkNetworkConnectivity());
@@ -289,8 +290,8 @@
// connect to Wifi
assertTrue("failed to connect to " + mTestAccessPoint,
connectToWifi(mTestAccessPoint));
- assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- WIFI_CONNECTION_TIMEOUT));
+ assertTrue("wifi not connected", waitForNetworkState(
+ ConnectivityManager.TYPE_WIFI, State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
// enable airplane mode without clearing Wifi
mCm.setAirplaneMode(true);
@@ -322,8 +323,8 @@
// connect to Wifi
assertTrue("failed to connect to " + mTestAccessPoint,
connectToWifi(mTestAccessPoint));
- assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- WIFI_CONNECTION_TIMEOUT));
+ assertTrue("wifi not connected", waitForNetworkState(
+ ConnectivityManager.TYPE_WIFI, State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
assertNotNull("not associated with any AP", mWifiManager.getConnectionInfo().getBSSID());
// disconnect from the current AP
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 859c30c..6ef4f06 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -198,6 +198,9 @@
// Stress Wifi reconnection to secure net after sleep
@LargeTest
public void testWifiReconnectionAfterSleep() {
+ // set always scan to false
+ Settings.Global.putInt(mRunner.getContext().getContentResolver(),
+ Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0);
// set wifi sleep policy to never on while in sleep
Settings.Global.putInt(mRunner.getContext().getContentResolver(),
Settings.Global.WIFI_SLEEP_POLICY, Settings.Global.WIFI_SLEEP_POLICY_NEVER);
diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
index 4ea1c77..c650a0f 100644
--- a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
+++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
@@ -76,6 +76,12 @@
}
@Override
+ public void onTrustTimeout() {
+ super.onTrustTimeout();
+ Toast.makeText(this, "onTrustTimeout(): timeout expired", Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
public void onUnlockAttempt(boolean successful) {
if (getReportUnlockAttempts(this)) {
Toast.makeText(this, "onUnlockAttempt(successful=" + successful + ")",
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index 1768400..03d920a 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -28,5 +28,14 @@
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
+
+ <activity android:name=".ManageDialog"
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
+ android:noHistory="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/packages/VpnDialogs/res/layout/manage.xml b/packages/VpnDialogs/res/layout/manage.xml
new file mode 100644
index 0000000..6b504e4
--- /dev/null
+++ b/packages/VpnDialogs/res/layout/manage.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="3mm"
+ android:stretchColumns="0,1"
+ android:shrinkColumns="1">
+
+ <TableRow>
+ <TextView android:text="@string/session" style="@style/label"/>
+ <TextView android:id="@+id/session" style="@style/value"/>
+ </TableRow>
+
+ <TableRow>
+ <TextView android:text="@string/duration" style="@style/label"/>
+ <TextView android:id="@+id/duration" style="@style/value"/>
+ </TableRow>
+
+ <TableRow android:id="@+id/data_transmitted_row" android:visibility="gone">
+ <TextView android:text="@string/data_transmitted" style="@style/label"/>
+ <TextView android:id="@+id/data_transmitted" style="@style/value"/>
+ </TableRow>
+
+ <TableRow android:id="@+id/data_received_row" android:visibility="gone">
+ <TextView android:text="@string/data_received" style="@style/label"/>
+ <TextView android:id="@+id/data_received" style="@style/value"/>
+ </TableRow>
+
+</TableLayout>
+
diff --git a/packages/VpnDialogs/res/values/strings.xml b/packages/VpnDialogs/res/values/strings.xml
index 84206a1..406bcc3 100644
--- a/packages/VpnDialogs/res/values/strings.xml
+++ b/packages/VpnDialogs/res/values/strings.xml
@@ -28,4 +28,26 @@
<img src="vpn_icon" />
]]> appears at the top of your screen when VPN is active.
</string>
+
+ <!-- Dialog title for built-in VPN. [CHAR LIMIT=40] -->
+ <string name="legacy_title">VPN is connected</string>
+ <!-- Button label to configure the current VPN session. [CHAR LIMIT=20] -->
+ <string name="configure">Configure</string>
+ <!-- Button label to disconnect the current VPN session. [CHAR LIMIT=20] -->
+ <string name="disconnect">Disconnect</string>
+
+ <!-- Label for the name of the current VPN session. [CHAR LIMIT=20] -->
+ <string name="session">Session:</string>
+ <!-- Label for the duration of the current VPN session. [CHAR LIMIT=20] -->
+ <string name="duration">Duration:</string>
+ <!-- Label for the network usage of data transmitted over VPN. [CHAR LIMIT=20] -->
+ <string name="data_transmitted">Sent:</string>
+ <!-- Label for the network usage of data received over VPN. [CHAR LIMIT=20] -->
+ <string name="data_received">Received:</string>
+
+ <!-- Formatted string for the network usage over VPN. [CHAR LIMIT=40] -->
+ <string name="data_value_format">
+ <xliff:g id="number">%1$s</xliff:g> bytes /
+ <xliff:g id="number">%2$s</xliff:g> packets
+ </string>
</resources>
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
new file mode 100644
index 0000000..cc8500a
--- /dev/null
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2011 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.vpndialogs;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.net.IConnectivityManager;
+import android.os.Handler;
+import android.os.Message;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.net.VpnConfig;
+
+import java.io.DataInputStream;
+import java.io.FileInputStream;
+
+public class ManageDialog extends AlertActivity implements
+ DialogInterface.OnClickListener, Handler.Callback {
+ private static final String TAG = "VpnManage";
+
+ private VpnConfig mConfig;
+
+ private IConnectivityManager mService;
+
+ private TextView mDuration;
+ private TextView mDataTransmitted;
+ private TextView mDataReceived;
+ private boolean mDataRowsHidden;
+
+ private Handler mHandler;
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ if (getCallingPackage() != null) {
+ Log.e(TAG, getCallingPackage() + " cannot start this activity");
+ finish();
+ return;
+ }
+
+ try {
+
+ mService = IConnectivityManager.Stub.asInterface(
+ ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
+
+ mConfig = mService.getVpnConfig();
+
+ // mConfig can be null if we are a restricted user, in that case don't show this dialog
+ if (mConfig == null) {
+ finish();
+ return;
+ }
+
+ View view = View.inflate(this, R.layout.manage, null);
+ if (mConfig.session != null) {
+ ((TextView) view.findViewById(R.id.session)).setText(mConfig.session);
+ }
+ mDuration = (TextView) view.findViewById(R.id.duration);
+ mDataTransmitted = (TextView) view.findViewById(R.id.data_transmitted);
+ mDataReceived = (TextView) view.findViewById(R.id.data_received);
+ mDataRowsHidden = true;
+
+ if (mConfig.legacy) {
+ mAlertParams.mTitle = getText(R.string.legacy_title);
+ } else {
+ mAlertParams.mTitle = VpnConfig.getVpnLabel(this, mConfig.user);
+ }
+ if (mConfig.configureIntent != null) {
+ mAlertParams.mPositiveButtonText = getText(R.string.configure);
+ mAlertParams.mPositiveButtonListener = this;
+ }
+ mAlertParams.mNeutralButtonText = getText(R.string.disconnect);
+ mAlertParams.mNeutralButtonListener = this;
+ mAlertParams.mNegativeButtonText = getText(android.R.string.cancel);
+ mAlertParams.mNegativeButtonListener = this;
+ mAlertParams.mView = view;
+ setupAlert();
+
+ if (mHandler == null) {
+ mHandler = new Handler(this);
+ }
+ mHandler.sendEmptyMessage(0);
+ } catch (Exception e) {
+ Log.e(TAG, "onResume", e);
+ finish();
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (!isFinishing()) {
+ finish();
+ }
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ try {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ mConfig.configureIntent.send();
+ } else if (which == DialogInterface.BUTTON_NEUTRAL) {
+ if (mConfig.legacy) {
+ mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
+ } else {
+ mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "onClick", e);
+ finish();
+ }
+ }
+
+ @Override
+ public boolean handleMessage(Message message) {
+ mHandler.removeMessages(0);
+
+ if (!isFinishing()) {
+ if (mConfig.startTime != -1) {
+ long seconds = (SystemClock.elapsedRealtime() - mConfig.startTime) / 1000;
+ mDuration.setText(String.format("%02d:%02d:%02d",
+ seconds / 3600, seconds / 60 % 60, seconds % 60));
+ }
+
+ String[] numbers = getNumbers();
+ if (numbers != null) {
+ // First unhide the related data rows.
+ if (mDataRowsHidden) {
+ findViewById(R.id.data_transmitted_row).setVisibility(View.VISIBLE);
+ findViewById(R.id.data_received_row).setVisibility(View.VISIBLE);
+ mDataRowsHidden = false;
+ }
+
+ // [1] and [2] are received data in bytes and packets.
+ mDataReceived.setText(getString(R.string.data_value_format,
+ numbers[1], numbers[2]));
+
+ // [9] and [10] are transmitted data in bytes and packets.
+ mDataTransmitted.setText(getString(R.string.data_value_format,
+ numbers[9], numbers[10]));
+ }
+ mHandler.sendEmptyMessageDelayed(0, 1000);
+ }
+ return true;
+ }
+
+ private String[] getNumbers() {
+ DataInputStream in = null;
+ try {
+ // See dev_seq_printf_stats() in net/core/dev.c.
+ in = new DataInputStream(new FileInputStream("/proc/net/dev"));
+ String prefix = mConfig.interfaze + ':';
+
+ while (true) {
+ String line = in.readLine().trim();
+ if (line.startsWith(prefix)) {
+ String[] numbers = line.substring(prefix.length()).split(" +");
+ for (int i = 1; i < 17; ++i) {
+ if (!numbers[i].equals("0")) {
+ return numbers;
+ }
+ }
+ break;
+ }
+ }
+ } catch (Exception e) {
+ // ignore
+ } finally {
+ try {
+ in.close();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ return null;
+ }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
index 394c196..38827d0 100644
--- a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
@@ -60,15 +60,17 @@
public static boolean hasAdjustments(Context context, int userId) {
final ContentResolver cr = context.getContentResolver();
- boolean hasColorTransform = Settings.Secure.getIntForUser(
- cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) == 1;
-
- if (!hasColorTransform) {
- hasColorTransform |= Settings.Secure.getIntForUser(
- cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) == 1;
+ if (Settings.Secure.getIntForUser(cr,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0) {
+ return true;
}
- return hasColorTransform;
+ if (Settings.Secure.getIntForUser(cr,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) {
+ return true;
+ }
+
+ return false;
}
/**
@@ -76,52 +78,39 @@
*/
public static void applyAdjustments(Context context, int userId) {
final ContentResolver cr = context.getContentResolver();
- float[] colorMatrix = new float[16];
- float[] outputMatrix = new float[16];
- boolean hasColorTransform = false;
+ float[] colorMatrix = null;
- Matrix.setIdentityM(colorMatrix, 0);
-
- final boolean inversionEnabled = Settings.Secure.getIntForUser(
- cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) == 1;
- if (inversionEnabled) {
- final float[] inversionMatrix = INVERSION_MATRIX_VALUE_ONLY;
- Matrix.multiplyMM(outputMatrix, 0, colorMatrix, 0, inversionMatrix, 0);
-
- colorMatrix = outputMatrix;
- outputMatrix = colorMatrix;
-
- hasColorTransform = true;
+ if (Settings.Secure.getIntForUser(cr,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0) {
+ colorMatrix = multiply(colorMatrix, INVERSION_MATRIX_VALUE_ONLY);
}
- final boolean daltonizerEnabled = Settings.Secure.getIntForUser(
- cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0;
- if (daltonizerEnabled) {
+ if (Settings.Secure.getIntForUser(cr,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) {
final int daltonizerMode = Settings.Secure.getIntForUser(cr,
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, DEFAULT_DISPLAY_DALTONIZER,
userId);
// Monochromacy isn't supported by the native Daltonizer.
if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
- Matrix.multiplyMM(outputMatrix, 0, colorMatrix, 0, GRAYSCALE_MATRIX, 0);
-
- final float[] temp = colorMatrix;
- colorMatrix = outputMatrix;
- outputMatrix = temp;
-
- hasColorTransform = true;
- nativeSetDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
+ colorMatrix = multiply(colorMatrix, GRAYSCALE_MATRIX);
+ setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
} else {
- nativeSetDaltonizerMode(daltonizerMode);
+ setDaltonizerMode(daltonizerMode);
}
} else {
- nativeSetDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
+ setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
}
- if (hasColorTransform) {
- nativeSetColorTransform(colorMatrix);
- } else {
- nativeSetColorTransform(null);
+ setColorTransform(colorMatrix);
+ }
+
+ private static float[] multiply(float[] matrix, float[] other) {
+ if (matrix == null) {
+ return other;
}
+ float[] result = new float[16];
+ Matrix.multiplyMM(result, 0, matrix, 0, other, 0);
+ return result;
}
/**
@@ -130,7 +119,7 @@
*
* @param mode new Daltonization mode
*/
- private static void nativeSetDaltonizerMode(int mode) {
+ private static void setDaltonizerMode(int mode) {
try {
final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
if (flinger != null) {
@@ -152,7 +141,7 @@
* @param m the float array that holds the transformation matrix, or null to
* disable transformation
*/
- private static void nativeSetColorTransform(float[] m) {
+ private static void setColorTransform(float[] m) {
try {
final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
if (flinger != null) {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 69caab9..94aa421 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -22,6 +22,7 @@
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -105,6 +106,7 @@
private boolean mAllowIPv6;
private Connection mConnection;
private LegacyVpnRunner mLegacyVpnRunner;
+ private PendingIntent mStatusIntent;
private volatile boolean mEnableTeardown = true;
private final IConnectivityManager mConnService;
private final INetworkManagementService mNetd;
@@ -237,6 +239,7 @@
// Reset the interface.
if (mInterface != null) {
+ mStatusIntent = null;
agentDisconnect();
jniReset(mInterface);
mInterface = null;
@@ -567,17 +570,20 @@
// add the user
mVpnUsers.add(UidRange.createForUser(user));
+
+ prepareStatusIntent();
}
private void removeVpnUserLocked(int user) {
- if (!isRunningLocked()) {
- throw new IllegalStateException("VPN is not active");
- }
- UidRange uidRange = UidRange.createForUser(user);
- if (mNetworkAgent != null) {
- mNetworkAgent.removeUidRanges(new UidRange[] { uidRange });
- }
- mVpnUsers.remove(uidRange);
+ if (!isRunningLocked()) {
+ throw new IllegalStateException("VPN is not active");
+ }
+ UidRange uidRange = UidRange.createForUser(user);
+ if (mNetworkAgent != null) {
+ mNetworkAgent.removeUidRanges(new UidRange[] { uidRange });
+ }
+ mVpnUsers.remove(uidRange);
+ mStatusIntent = null;
}
private void onUserAdded(int userId) {
@@ -645,6 +651,7 @@
public void interfaceRemoved(String interfaze) {
synchronized (Vpn.this) {
if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
+ mStatusIntent = null;
mVpnUsers = null;
mInterface = null;
if (mConnection != null) {
@@ -702,6 +709,15 @@
}
}
+ private void prepareStatusIntent() {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
public synchronized boolean addAddress(String address, int prefixLength) {
if (Binder.getCallingUid() != mOwnerUID || mInterface == null || mNetworkAgent == null) {
return false;
@@ -911,6 +927,9 @@
final LegacyVpnInfo info = new LegacyVpnInfo();
info.key = mConfig.user;
info.state = LegacyVpnInfo.stateFromNetworkInfo(mNetworkInfo);
+ if (mNetworkInfo.isConnected()) {
+ info.intent = mStatusIntent;
+ }
return info;
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 2a1ceaa..38077eb 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -139,6 +139,9 @@
// The dim screen brightness.
private final int mScreenBrightnessDimConfig;
+ // The minimum screen brightness to use in a very dark room.
+ private final int mScreenBrightnessDarkConfig;
+
// The minimum allowed brightness.
private final int mScreenBrightnessRangeMinimum;
@@ -247,6 +250,8 @@
mContext = context;
final Resources resources = context.getResources();
+ final int screenBrightnessSettingMinimum = clampAbsoluteBrightness(resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessSettingMinimum));
mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessDoze));
@@ -254,9 +259,23 @@
mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessDim));
- int screenBrightnessRangeMinimum = clampAbsoluteBrightness(Math.min(resources.getInteger(
- com.android.internal.R.integer.config_screenBrightnessSettingMinimum),
- mScreenBrightnessDimConfig));
+ mScreenBrightnessDarkConfig = clampAbsoluteBrightness(resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessDark));
+ if (mScreenBrightnessDarkConfig > mScreenBrightnessDimConfig) {
+ Slog.w(TAG, "Expected config_screenBrightnessDark ("
+ + mScreenBrightnessDarkConfig + ") to be less than or equal to "
+ + "config_screenBrightnessDim (" + mScreenBrightnessDimConfig + ").");
+ }
+ if (mScreenBrightnessDarkConfig > mScreenBrightnessDimConfig) {
+ Slog.w(TAG, "Expected config_screenBrightnessDark ("
+ + mScreenBrightnessDarkConfig + ") to be less than or equal to "
+ + "config_screenBrightnessSettingMinimum ("
+ + screenBrightnessSettingMinimum + ").");
+ }
+
+ int screenBrightnessRangeMinimum = Math.min(Math.min(
+ screenBrightnessSettingMinimum, mScreenBrightnessDimConfig),
+ mScreenBrightnessDarkConfig);
mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
@@ -280,8 +299,15 @@
+ "Auto-brightness will be disabled.");
mUseSoftwareAutoBrightnessConfig = false;
} else {
- if (screenBrightness[0] < screenBrightnessRangeMinimum) {
- screenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightness[0]);
+ int bottom = clampAbsoluteBrightness(screenBrightness[0]);
+ if (mScreenBrightnessDarkConfig > bottom) {
+ Slog.w(TAG, "config_screenBrightnessDark (" + mScreenBrightnessDarkConfig
+ + ") should be less than or equal to the first value of "
+ + "config_autoBrightnessLcdBacklightValues ("
+ + bottom + ").");
+ }
+ if (bottom < screenBrightnessRangeMinimum) {
+ screenBrightnessRangeMinimum = bottom;
}
mAutomaticBrightnessController = new AutomaticBrightnessController(this,
handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
@@ -905,6 +931,7 @@
pw.println("Display Power Controller Configuration:");
pw.println(" mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
+ pw.println(" mScreenBrightnessDarkConfig=" + mScreenBrightnessDarkConfig);
pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
pw.println(" mUseSoftwareAutoBrightnessConfig="
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 9734bd4..f47a07c 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -160,9 +160,9 @@
// Poll interval in milliseconds for watching boot animation finished.
private static final int BOOT_ANIMATION_POLL_INTERVAL = 200;
- // Used to send the hint to the PowerHAL indicating transitions
- // from and to the low power mode.
- private static final int POWER_HINT_LOW_POWER_MODE = 5;
+ // Power hints defined in hardware/libhardware/include/hardware/power.h.
+ private static final int POWER_HINT_INTERACTION = 2;
+ private static final int POWER_HINT_LOW_POWER = 5;
private final Context mContext;
private final ServiceThread mHandlerThread;
@@ -223,6 +223,9 @@
private long mLastUserActivityTime;
private long mLastUserActivityTimeNoChangeLights;
+ // Timestamp of last interactive power hint.
+ private long mLastInteractivePowerHintTime;
+
// A bitfield that summarizes the effect of the user activity timer.
// A zero value indicates that the user activity timer has expired.
private int mUserActivitySummary;
@@ -707,7 +710,7 @@
final boolean lowPowerModeEnabled = mLowPowerModeSetting;
if (mLowPowerModeEnabled != lowPowerModeEnabled) {
mLowPowerModeEnabled = lowPowerModeEnabled;
- powerHintInternal(POWER_HINT_LOW_POWER_MODE, lowPowerModeEnabled ? 1 : 0);
+ powerHintInternal(POWER_HINT_LOW_POWER, lowPowerModeEnabled ? 1 : 0);
mLowPowerModeEnabled = lowPowerModeEnabled;
BackgroundThread.getHandler().post(new Runnable() {
@Override
@@ -969,15 +972,25 @@
}
if (eventTime < mLastSleepTime || eventTime < mLastWakeTime
- || mWakefulness == WAKEFULNESS_ASLEEP || mWakefulness == WAKEFULNESS_DOZING
|| !mBootCompleted || !mSystemReady) {
return false;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "userActivity");
try {
+ if (eventTime > mLastInteractivePowerHintTime) {
+ powerHintInternal(POWER_HINT_INTERACTION, 0);
+ mLastInteractivePowerHintTime = eventTime;
+ }
+
mNotifier.onUserActivity(event, uid);
+ if (mWakefulness == WAKEFULNESS_ASLEEP
+ || mWakefulness == WAKEFULNESS_DOZING
+ || (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
+ return false;
+ }
+
if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
if (eventTime > mLastUserActivityTimeNoChangeLights
&& eventTime > mLastUserActivityTime) {
@@ -2319,6 +2332,8 @@
pw.println(" mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime));
pw.println(" mLastUserActivityTimeNoChangeLights="
+ TimeUtils.formatUptime(mLastUserActivityTimeNoChangeLights));
+ pw.println(" mLastInteractivePowerHintTime="
+ + TimeUtils.formatUptime(mLastInteractivePowerHintTime));
pw.println(" mDisplayReady=" + mDisplayReady);
pw.println(" mHoldingWakeLockSuspendBlocker=" + mHoldingWakeLockSuspendBlocker);
pw.println(" mHoldingDisplaySuspendBlocker=" + mHoldingDisplaySuspendBlocker);
@@ -2774,6 +2789,10 @@
PowerManager.validateWakeLockParameters(flags, tag);
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
+ if ((flags & PowerManager.DOZE_WAKE_LOCK) != 0) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.DEVICE_POWER, null);
+ }
if (ws != null && ws.size() != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.UPDATE_DEVICE_STATS, null);
@@ -2859,7 +2878,10 @@
public void userActivity(long eventTime, int event, int flags) {
final long now = SystemClock.uptimeMillis();
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
- != PackageManager.PERMISSION_GRANTED) {
+ != PackageManager.PERMISSION_GRANTED
+ && mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.USER_ACTIVITY)
+ != PackageManager.PERMISSION_GRANTED) {
// Once upon a time applications could call userActivity().
// Now we require the DEVICE_POWER permission. Log a warning and ignore the
// request instead of throwing a SecurityException so we don't break old apps.
@@ -2867,8 +2889,8 @@
if (now >= mLastWarningAboutUserActivityPermission + (5 * 60 * 1000)) {
mLastWarningAboutUserActivityPermission = now;
Slog.w(TAG, "Ignoring call to PowerManager.userActivity() because the "
- + "caller does not have DEVICE_POWER permission. "
- + "Please fix your app! "
+ + "caller does not have DEVICE_POWER or USER_ACTIVITY "
+ + "permission. Please fix your app! "
+ " pid=" + Binder.getCallingPid()
+ " uid=" + Binder.getCallingUid());
}
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 0523af7..4c080cb 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -16,16 +16,22 @@
package com.android.server.trust;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
+import android.os.PatternMatcher;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -43,6 +49,9 @@
* TrustManager and the actual TrustAgent.
*/
public class TrustAgentWrapper {
+ private static final String EXTRA_COMPONENT_NAME = "componentName";
+ private static final String TRUST_EXPIRED_ACTION = "android.server.trust.TRUST_EXPIRED_ACTION";
+ private static final String PERMISSION = "android.permission.PROVIDE_TRUST_AGENT";
private static final boolean DEBUG = false;
private static final String TAG = "TrustAgentWrapper";
@@ -79,6 +88,20 @@
private boolean mTrustDisabledByDpm;
private boolean mManagingTrust;
private IBinder mSetTrustAgentFeaturesToken;
+ private AlarmManager mAlarmManager;
+ private final Intent mAlarmIntent;
+
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT_NAME);
+ if (TRUST_EXPIRED_ACTION.equals(intent.getAction())
+ && mName.equals(component)) {
+ mHandler.removeMessages(MSG_TRUST_TIMEOUT);
+ mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
+ }
+ }
+ };
private final Handler mHandler = new Handler() {
@Override
@@ -95,8 +118,10 @@
boolean initiatedByUser = msg.arg1 != 0;
long durationMs = msg.getData().getLong(DATA_DURATION);
if (durationMs > 0) {
- mHandler.removeMessages(MSG_TRUST_TIMEOUT);
- mHandler.sendEmptyMessageDelayed(MSG_TRUST_TIMEOUT, durationMs);
+ long expiration = SystemClock.elapsedRealtime() + durationMs;
+ PendingIntent op = PendingIntent.getBroadcast(mContext, 0, mAlarmIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, expiration, op);
}
mTrustManagerService.mArchive.logGrantTrust(mUserId, mName,
(mMessage != null ? mMessage.toString() : null),
@@ -106,6 +131,7 @@
case MSG_TRUST_TIMEOUT:
if (DEBUG) Slog.v(TAG, "Trust timed out : " + mName.flattenToShortString());
mTrustManagerService.mArchive.logTrustTimeout(mUserId, mName);
+ onTrustTimeout();
// Fall through.
case MSG_REVOKE_TRUST:
mTrusted = false;
@@ -212,8 +238,19 @@
Intent intent, UserHandle user) {
mContext = context;
mTrustManagerService = trustManagerService;
+ mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mUserId = user.getIdentifier();
mName = intent.getComponent();
+
+ mAlarmIntent = new Intent(TRUST_EXPIRED_ACTION).putExtra(EXTRA_COMPONENT_NAME, mName);
+ mAlarmIntent.setData(Uri.parse(mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME)));
+
+ final IntentFilter alarmFilter = new IntentFilter(TRUST_EXPIRED_ACTION);
+ alarmFilter.addDataScheme(mAlarmIntent.getScheme());
+ final String pathUri = mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME);
+ alarmFilter.addDataPath(pathUri, PatternMatcher.PATTERN_LITERAL);
+ mContext.registerReceiver(mBroadcastReceiver, alarmFilter);
+
// Schedules a restart for when connecting times out. If the connection succeeds,
// the restart is canceled in mCallback's onConnected.
scheduleRestart();
@@ -227,6 +264,13 @@
Slog.w(TAG , "Remote Exception", e);
}
+ private void onTrustTimeout() {
+ try {
+ if (mTrustAgentService != null) mTrustAgentService.onTrustTimeout();
+ } catch (RemoteException e) {
+ onError(e);
+ }
+ }
/**
* @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean)
*/
diff --git a/tools/aapt/ResourceFilter.cpp b/tools/aapt/ResourceFilter.cpp
index de8b4fc..fc95e14 100644
--- a/tools/aapt/ResourceFilter.cpp
+++ b/tools/aapt/ResourceFilter.cpp
@@ -56,24 +56,34 @@
return true;
}
+ uint32_t matchedAxis = 0x0;
const size_t N = mConfigs.size();
for (size_t i = 0; i < N; i++) {
const std::pair<ConfigDescription, uint32_t>& entry = mConfigs[i];
uint32_t diff = entry.first.diff(config);
if ((diff & entry.second) == 0) {
- return true;
+ // Mark the axis that was matched.
+ matchedAxis |= entry.second;
} else if ((diff & entry.second) == ResTable_config::CONFIG_LOCALE) {
// If the locales differ, but the languages are the same and
// the locale we are matching only has a language specified,
// we match.
- if (config.language[0] && memcmp(config.language, entry.first.language, sizeof(config.language)) == 0) {
+ if (config.language[0] &&
+ memcmp(config.language, entry.first.language, sizeof(config.language)) == 0) {
if (config.country[0] == 0) {
- return true;
+ matchedAxis |= ResTable_config::CONFIG_LOCALE;
}
}
+ } else if ((diff & entry.second) == ResTable_config::CONFIG_SMALLEST_SCREEN_SIZE) {
+ // Special case if the smallest screen width doesn't match. We check that the
+ // config being matched has a smaller screen width than the filter specified.
+ if (config.smallestScreenWidthDp != 0 &&
+ config.smallestScreenWidthDp < entry.first.smallestScreenWidthDp) {
+ matchedAxis |= ResTable_config::CONFIG_SMALLEST_SCREEN_SIZE;
+ }
}
}
- return false;
+ return matchedAxis == (mConfigMask & mask);
}
status_t
diff --git a/tools/aapt/ResourceFilter.h b/tools/aapt/ResourceFilter.h
index f459584..d6430c0 100644
--- a/tools/aapt/ResourceFilter.h
+++ b/tools/aapt/ResourceFilter.h
@@ -24,8 +24,7 @@
};
/**
- * Implements logic for parsing and handling "-c" and "--preferred-configurations"
- * options.
+ * Implements logic for parsing and handling "-c" options.
*/
class WeakResourceFilter : public ResourceFilter {
public:
diff --git a/tools/aapt/tests/ResourceFilter_test.cpp b/tools/aapt/tests/ResourceFilter_test.cpp
index b55379e..bbc2e02 100644
--- a/tools/aapt/tests/ResourceFilter_test.cpp
+++ b/tools/aapt/tests/ResourceFilter_test.cpp
@@ -75,6 +75,17 @@
EXPECT_TRUE(filter.match(config));
}
+TEST(WeakResourceFilterTest, MatchesConfigWithOneMatchingAxis) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("fr_FR,sw360dp,normal,en_US")));
+
+ ConfigDescription config;
+ config.language[0] = 'e';
+ config.language[1] = 'n';
+
+ EXPECT_TRUE(filter.match(config));
+}
+
TEST(WeakResourceFilterTest, DoesNotMatchConfigWithDifferentValueAxis) {
WeakResourceFilter filter;
ASSERT_EQ(NO_ERROR, filter.parse(String8("fr")));
@@ -86,6 +97,32 @@
EXPECT_FALSE(filter.match(config));
}
+TEST(WeakResourceFilterTest, DoesNotMatchWhenOneQualifierIsExplicitlyNotMatched) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("fr_FR,en_US,normal,large,xxhdpi,sw320dp")));
+
+ ConfigDescription config;
+ config.language[0] = 'f';
+ config.language[1] = 'r';
+ config.smallestScreenWidthDp = 600;
+ config.version = 13;
+
+ EXPECT_FALSE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesSmallestWidthWhenSmaller) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("sw600dp")));
+
+ ConfigDescription config;
+ config.language[0] = 'f';
+ config.language[1] = 'r';
+ config.smallestScreenWidthDp = 320;
+ config.version = 13;
+
+ EXPECT_TRUE(filter.match(config));
+}
+
TEST(WeakResourceFilterTest, MatchesConfigWithSameLanguageButNoRegionSpecified) {
WeakResourceFilter filter;
ASSERT_EQ(NO_ERROR, filter.parse(String8("de-rDE")));