diff options
31 files changed, 761 insertions, 158 deletions
diff --git a/api/current.txt b/api/current.txt index 20c4db9e0102..a592b0eaa136 100644 --- a/api/current.txt +++ b/api/current.txt @@ -22465,21 +22465,21 @@ package android.os { } 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 @@ package android.os { 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 465a18d76efb..93484de155aa 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -6,6 +6,16 @@ package android.media { } +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 0dc8f66bb640..41bbb87e55e9 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1373,6 +1373,8 @@ public class DevicePolicyManager { * 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 75f8279c6c12..f7b0eadea8ba 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 @@ public final class PowerManager { * </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 @@ public final class PowerManager { * <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 final class PowerManager { 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 @@ public final class PowerManager { * 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 final class PowerManager { 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 final class PowerManager { */ 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 @@ public final class PowerManager { * @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 @@ public final class PowerManager { * * @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 @@ public final class PowerManager { * * @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 @@ public final class PowerManager { * * @see #userActivity * @see #goToSleep + * + * @removed Requires signature permission. */ public void wakeUp(long time) { try { @@ -588,7 +659,7 @@ public final class PowerManager { * @see #wakeUp * @see #goToSleep * - * @hide + * @hide Requires signature permission. */ public void nap(long time) { try { @@ -605,7 +676,7 @@ public final class PowerManager { * * @param brightness The brightness value from 0 to 255. * - * {@hide} + * @hide Requires signature permission. */ public void setBacklightBrightness(int brightness) { try { @@ -619,8 +690,6 @@ public final class PowerManager { * * @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 @@ public final class PowerManager { * * @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 637d08070619..bd80a3fa4a86 100644 --- a/core/java/android/service/trust/ITrustAgentService.aidl +++ b/core/java/android/service/trust/ITrustAgentService.aidl @@ -24,6 +24,7 @@ import android.service.trust.ITrustAgentServiceCallback; */ 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 5fe9194d7401..337ae60c5f2a 100644 --- a/core/java/android/service/trust/TrustAgentService.java +++ b/core/java/android/service/trust/TrustAgentService.java @@ -30,6 +30,7 @@ import android.os.Handler; 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 @@ import android.util.Slog; * 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 @@ public class TrustAgentService extends Service { 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 @@ public class TrustAgentService extends Service { onError("calling onSetTrustAgentFeaturesEnabledCompleted()"); } break; + case MSG_TRUST_TIMEOUT: + onTrustTimeout(); + break; } } }; @@ -139,21 +147,32 @@ public class TrustAgentService extends Service { } /** - * 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 @@ public class TrustAgentService extends Service { * 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 @@ public class TrustAgentService extends Service { } 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 /* Binder API */ + public void onTrustTimeout() { + mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT); } - @Override + @Override /* Binder API */ public void setCallback(ITrustAgentServiceCallback callback) { synchronized (mLock) { mCallback = callback; @@ -280,7 +312,7 @@ public class TrustAgentService extends Service { } } - @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 096fe88811ab..9b3a1e001c29 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -5719,8 +5719,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } if (mEditor != null && mEditor.mKeyListener != null) { - resetErrorChangedFlag(); - boolean doDown = true; if (otherEvent != null) { try { @@ -7637,6 +7635,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener list.get(i).afterTextChanged(text); } } + hideErrorIfUnchanged(); } void updateAfterEdit() { @@ -7676,7 +7675,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } 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 1b89179d6028..ae44047aae38 100644 --- a/core/java/android/widget/TimePickerClockDelegate.java +++ b/core/java/android/widget/TimePickerClockDelegate.java @@ -37,6 +37,8 @@ import com.android.internal.R; 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 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { 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 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { } }; } -} + 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 9a50250587cf..dd1bf4f2b8a6 100644 --- a/core/java/android/widget/TimePickerSpinnerDelegate.java +++ b/core/java/android/widget/TimePickerSpinnerDelegate.java @@ -127,8 +127,10 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im 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 f812ad6ae325..d6f6d0bac1a0 100644 --- a/core/java/com/android/internal/net/LegacyVpnInfo.java +++ b/core/java/com/android/internal/net/LegacyVpnInfo.java @@ -40,6 +40,7 @@ public class LegacyVpnInfo implements Parcelable { public String key; public int state = -1; + public PendingIntent intent; @Override public int describeContents() { @@ -50,6 +51,7 @@ public class LegacyVpnInfo implements Parcelable { 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 @@ public class LegacyVpnInfo implements Parcelable { 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 aa66d7df464b..9c3f419a3a46 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.LinkAddress; 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 @@ public class VpnConfig implements Parcelable { 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 0a395e10e948..672ad8444b27 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 000000000000..4c0562fcf4ca --- /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 c6478abf57d8..4f0757cade5a 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 1453e1543908..b167c0ac32dd 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 b5ec56a491df..3f373aabde83 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 b4b0e53c7321..01995c774493 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 @@ public class ConnectivityManagerMobileTest extends 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 @@ public class ConnectivityManagerMobileTest extends // 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 @@ public class ConnectivityManagerMobileTest extends // 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 @@ public class ConnectivityManagerMobileTest extends // 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 859c30c28a3e..6ef4f063a958 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 @@ public class WifiStressTest extends ConnectivityManagerTestBase { // 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 4ea1c772806c..c650a0f0c158 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 @@ public class SampleTrustAgent extends TrustAgentService } @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 1768400862a6..03d920a4b71b 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 000000000000..6b504e47ceab --- /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 84206a164ec8..406bcc34a101 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 000000000000..cc8500ae34a8 --- /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 394c196c9a60..38827d09c99f 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 @@ class DisplayAdjustmentUtils { 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 (Settings.Secure.getIntForUser(cr, + Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0) { + return true; + } - 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_DALTONIZER_ENABLED, 0, userId) != 0) { + return true; } - return hasColorTransform; + return false; } /** @@ -76,52 +78,39 @@ class DisplayAdjustmentUtils { */ 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; - - 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); + float[] colorMatrix = null; - 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 @@ class DisplayAdjustmentUtils { * * @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 @@ class DisplayAdjustmentUtils { * @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 69caab98f3e4..94aa421dd1bf 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 static android.system.OsConstants.AF_INET6; 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 @@ public class Vpn { 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 @@ public class Vpn { // Reset the interface. if (mInterface != null) { + mStatusIntent = null; agentDisconnect(); jniReset(mInterface); mInterface = null; @@ -567,17 +570,20 @@ public class Vpn { // 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 class Vpn { 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 @@ public class Vpn { } } + 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 @@ public class Vpn { 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 2a1ceaac2b56..38077ebb5a26 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 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // 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 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call 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 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call 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 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call + "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 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call 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 9734bd4579bc..f47a07ca050e 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 @@ public final class PowerManagerService extends com.android.server.SystemService // 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 @@ public final class PowerManagerService extends com.android.server.SystemService 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 @@ public final class PowerManagerService extends com.android.server.SystemService 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 @@ public final class PowerManagerService extends com.android.server.SystemService } 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 @@ public final class PowerManagerService extends com.android.server.SystemService 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 @@ public final class PowerManagerService extends com.android.server.SystemService 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 final class PowerManagerService extends com.android.server.SystemService 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 @@ public final class PowerManagerService extends com.android.server.SystemService 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 0523af71d7a3..4c080cbac201 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 @@ import java.util.List; * 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 @@ public class TrustAgentWrapper { 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 @@ public class TrustAgentWrapper { 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 @@ public class TrustAgentWrapper { 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 @@ public class TrustAgentWrapper { 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 @@ public class TrustAgentWrapper { 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 de8b4fccb369..fc95e148ea41 100644 --- a/tools/aapt/ResourceFilter.cpp +++ b/tools/aapt/ResourceFilter.cpp @@ -56,24 +56,34 @@ WeakResourceFilter::match(const ResTable_config& config) const 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 f459584a1af9..d6430c0409cc 100644 --- a/tools/aapt/ResourceFilter.h +++ b/tools/aapt/ResourceFilter.h @@ -24,8 +24,7 @@ public: }; /** - * 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 b55379ebf05d..bbc2e02a4de2 100644 --- a/tools/aapt/tests/ResourceFilter_test.cpp +++ b/tools/aapt/tests/ResourceFilter_test.cpp @@ -75,6 +75,17 @@ TEST(WeakResourceFilterTest, MatchesConfigWithSameValueAxisAndOtherUnrelatedAxis 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 @@ TEST(WeakResourceFilterTest, DoesNotMatchConfigWithDifferentValueAxis) { 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"))); |