diff options
Diffstat (limited to 'core/java')
64 files changed, 2641 insertions, 766 deletions
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java index 20236aa..933135d 100644 --- a/core/java/android/animation/AnimatorInflater.java +++ b/core/java/android/animation/AnimatorInflater.java @@ -21,6 +21,7 @@ import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.content.res.Resources.NotFoundException; import android.util.AttributeSet; +import android.util.StateSet; import android.util.TypedValue; import android.util.Xml; import android.view.animation.AnimationUtils; @@ -87,9 +88,86 @@ public class AnimatorInflater { } } + public static StateListAnimator loadStateListAnimator(Context context, int id) + throws NotFoundException { + XmlResourceParser parser = null; + try { + parser = context.getResources().getAnimation(id); + return createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser)); + } catch (XmlPullParserException ex) { + Resources.NotFoundException rnf = + new Resources.NotFoundException( + "Can't load state list animator resource ID #0x" + + Integer.toHexString(id) + ); + rnf.initCause(ex); + throw rnf; + } catch (IOException ex) { + Resources.NotFoundException rnf = + new Resources.NotFoundException( + "Can't load state list animator resource ID #0x" + + Integer.toHexString(id) + ); + rnf.initCause(ex); + throw rnf; + } finally { + if (parser != null) { + parser.close(); + } + } + } + + private static StateListAnimator createStateListAnimatorFromXml(Context context, + XmlPullParser parser, AttributeSet attributeSet) + throws IOException, XmlPullParserException { + int type; + StateListAnimator stateListAnimator = new StateListAnimator(); + + while (true) { + type = parser.next(); + switch (type) { + case XmlPullParser.END_DOCUMENT: + case XmlPullParser.END_TAG: + return stateListAnimator; + + case XmlPullParser.START_TAG: + // parse item + Animator animator = null; + if ("item".equals(parser.getName())) { + int attributeCount = parser.getAttributeCount(); + int[] states = new int[attributeCount]; + int stateIndex = 0; + for (int i = 0; i < attributeCount; i++) { + int attrName = attributeSet.getAttributeNameResource(i); + if (attrName == com.android.internal.R.attr.animation) { + animator = loadAnimator(context, + attributeSet.getAttributeResourceValue(i, 0)); + } else { + states[stateIndex++] = + attributeSet.getAttributeBooleanValue(i, false) ? + attrName : -attrName; + } + + } + if (animator == null) { + animator = createAnimatorFromXml(context, parser); + } + + if (animator == null) { + throw new Resources.NotFoundException( + "animation state item must have a valid animation"); + } + stateListAnimator + .addState(StateSet.trimStateSet(states, stateIndex), animator); + + } + break; + } + } + } + private static Animator createAnimatorFromXml(Context c, XmlPullParser parser) throws XmlPullParserException, IOException { - return createAnimatorFromXml(c, parser, Xml.asAttributeSet(parser), null, 0); } diff --git a/core/java/android/animation/StateListAnimator.java b/core/java/android/animation/StateListAnimator.java new file mode 100644 index 0000000..bc4843d --- /dev/null +++ b/core/java/android/animation/StateListAnimator.java @@ -0,0 +1,209 @@ +/* + * 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. + */ + +package android.animation; + +import android.util.StateSet; +import android.view.View; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; + +/** + * Lets you define a number of Animators that will run on the attached View depending on the View's + * drawable state. + * <p> + * It can be defined in an XML file with the <code><selector></code> element. + * Each State Animator is defined in a nested <code><item></code> element. + * + * @attr ref android.R.styleable#DrawableStates_state_focused + * @attr ref android.R.styleable#DrawableStates_state_window_focused + * @attr ref android.R.styleable#DrawableStates_state_enabled + * @attr ref android.R.styleable#DrawableStates_state_checkable + * @attr ref android.R.styleable#DrawableStates_state_checked + * @attr ref android.R.styleable#DrawableStates_state_selected + * @attr ref android.R.styleable#DrawableStates_state_activated + * @attr ref android.R.styleable#DrawableStates_state_active + * @attr ref android.R.styleable#DrawableStates_state_single + * @attr ref android.R.styleable#DrawableStates_state_first + * @attr ref android.R.styleable#DrawableStates_state_middle + * @attr ref android.R.styleable#DrawableStates_state_last + * @attr ref android.R.styleable#DrawableStates_state_pressed + * @attr ref android.R.styleable#StateListAnimatorItem_animation + */ +public class StateListAnimator { + + private final ArrayList<Tuple> mTuples = new ArrayList<Tuple>(); + + private Tuple mLastMatch = null; + + private Animator mRunningAnimator = null; + + private WeakReference<View> mViewRef; + + private AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (mRunningAnimator == animation) { + mRunningAnimator = null; + } + } + }; + + /** + * Associates the given animator with the provided drawable state specs so that it will be run + * when the View's drawable state matches the specs. + * + * @param specs The drawable state specs to match against + * @param animator The animator to run when the specs match + */ + public void addState(int[] specs, Animator animator) { + Tuple tuple = new Tuple(specs, animator); + tuple.mAnimator.addListener(mAnimatorListener); + mTuples.add(tuple); + } + + /** + * Returns the current {@link android.animation.Animator} which is started because of a state + * change. + * + * @return The currently running Animator or null if no Animator is running + * @hide + */ + public Animator getRunningAnimator() { + return mRunningAnimator; + } + + /** + * @hide + */ + public View getTarget() { + return mViewRef == null ? null : mViewRef.get(); + } + + /** + * Called by View + * @hide + */ + public void setTarget(View view) { + final View current = getTarget(); + if (current == view) { + return; + } + if (current != null) { + clearTarget(); + } + if (view != null) { + mViewRef = new WeakReference<View>(view); + } + + } + + private void clearTarget() { + final int size = mTuples.size(); + for (int i = 0; i < size; i++) { + mTuples.get(i).mAnimator.setTarget(null); + } + + mViewRef = null; + mLastMatch = null; + mRunningAnimator = null; + } + + /** + * Called by View + * @hide + */ + public void setState(int[] state) { + Tuple match = null; + final int count = mTuples.size(); + for (int i = 0; i < count; i++) { + final Tuple tuple = mTuples.get(i); + if (StateSet.stateSetMatches(tuple.mSpecs, state)) { + match = tuple; + break; + } + } + if (match == mLastMatch) { + return; + } + if (mLastMatch != null) { + cancel(mLastMatch); + } + mLastMatch = match; + if (match != null) { + start(match); + } + } + + private void start(Tuple match) { + match.mAnimator.setTarget(getTarget()); + mRunningAnimator = match.mAnimator; + match.mAnimator.start(); + } + + private void cancel(Tuple lastMatch) { + lastMatch.mAnimator.cancel(); + lastMatch.mAnimator.setTarget(null); + } + + /** + * @hide + */ + public ArrayList<Tuple> getTuples() { + return mTuples; + } + + /** + * If there is an animation running for a recent state change, ends it. + * <p> + * This causes the animation to assign the end value(s) to the View. + */ + public void jumpToCurrentState() { + if (mRunningAnimator != null) { + mRunningAnimator.end(); + } + } + + /** + * @hide + */ + public static class Tuple { + + final int[] mSpecs; + + final Animator mAnimator; + + private Tuple(int[] specs, Animator animator) { + mSpecs = specs; + mAnimator = animator; + } + + /** + * @hide + */ + public int[] getSpecs() { + return mSpecs; + } + + /** + * @hide + */ + public Animator getAnimator() { + return mAnimator; + } + } +} diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 2a9dcfe..66b82eb 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -30,6 +30,7 @@ import com.android.internal.policy.PolicyManager; import android.annotation.IntDef; import android.annotation.Nullable; +import android.app.admin.DevicePolicyManager; import android.content.ComponentCallbacks2; import android.content.ComponentName; import android.content.ContentResolver; @@ -4925,6 +4926,7 @@ public class Activity extends ContextThemeWrapper public void setRecentsActivityValues(ActivityManager.RecentsActivityValues values) { ActivityManager.RecentsActivityValues activityValues = new ActivityManager.RecentsActivityValues(values); + // Scale the icon down to something reasonable if (values.icon != null) { final int size = ActivityManager.getLauncherLargeIconSizeInner(this); activityValues.icon = Bitmap.createScaledBitmap(values.icon, size, size, true); @@ -5817,7 +5819,16 @@ public class Activity extends ContextThemeWrapper } } - /** @hide */ + /** + * Put this Activity in a mode where the user is locked to the + * current task. + * + * This will prevent the user from launching other apps, going to settings, + * or reaching the home screen. + * + * Lock task mode will only start if the activity has been whitelisted by the + * Device Owner through DevicePolicyManager#setLockTaskComponents. + */ public void startLockTask() { try { ActivityManagerNative.getDefault().startLockTaskMode(mToken); @@ -5825,7 +5836,15 @@ public class Activity extends ContextThemeWrapper } } - /** @hide */ + /** + * Allow the user to switch away from the current task. + * + * Called to end the mode started by {@link Activity#startLockTask}. This + * can only be called by activities that have successfully called + * startLockTask previously. + * + * This will allow the user to exit this app and move onto other activities. + */ public void stopLockTask() { try { ActivityManagerNative.getDefault().stopLockTaskMode(); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 5d809d8..044727d 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -20,7 +20,6 @@ import android.os.BatteryStats; import android.os.IBinder; import com.android.internal.app.IUsageStats; import com.android.internal.app.ProcessStats; -import com.android.internal.os.PkgUsageStats; import com.android.internal.os.TransferPipe; import com.android.internal.util.FastPrintWriter; @@ -2130,14 +2129,15 @@ public class ActivityManager { return new HashMap<String, Integer>(); } - PkgUsageStats[] allPkgUsageStats = usageStatsService.getAllPkgUsageStats(); + UsageStats.PackageStats[] allPkgUsageStats = usageStatsService.getAllPkgUsageStats( + ActivityThread.currentPackageName()); if (allPkgUsageStats == null) { return new HashMap<String, Integer>(); } Map<String, Integer> launchCounts = new HashMap<String, Integer>(); - for (PkgUsageStats pkgUsageStats : allPkgUsageStats) { - launchCounts.put(pkgUsageStats.packageName, pkgUsageStats.launchCount); + for (UsageStats.PackageStats pkgUsageStats : allPkgUsageStats) { + launchCounts.put(pkgUsageStats.getPackageName(), pkgUsageStats.getLaunchCount()); } return launchCounts; @@ -2251,17 +2251,17 @@ public class ActivityManager { * * @hide */ - public PkgUsageStats[] getAllPackageUsageStats() { + public UsageStats.PackageStats[] getAllPackageUsageStats() { try { IUsageStats usageStatsService = IUsageStats.Stub.asInterface( ServiceManager.getService("usagestats")); if (usageStatsService != null) { - return usageStatsService.getAllPkgUsageStats(); + return usageStatsService.getAllPkgUsageStats(ActivityThread.currentPackageName()); } } catch (RemoteException e) { Log.w(TAG, "Could not query usage stats", e); } - return new PkgUsageStats[0]; + return new UsageStats.PackageStats[0]; } /** diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 63594bf..161cb76 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -46,7 +46,7 @@ import android.graphics.Canvas; import android.hardware.display.DisplayManagerGlobal; import android.net.IConnectivityManager; import android.net.Proxy; -import android.net.ProxyProperties; +import android.net.ProxyInfo; import android.opengl.GLUtils; import android.os.AsyncTask; import android.os.Binder; @@ -4313,8 +4313,8 @@ public final class ActivityThread { // crash if we can't get it. IConnectivityManager service = IConnectivityManager.Stub.asInterface(b); try { - ProxyProperties proxyProperties = service.getProxy(); - Proxy.setHttpProxySystemProperty(proxyProperties); + ProxyInfo proxyInfo = service.getProxy(); + Proxy.setHttpProxySystemProperty(proxyInfo); } catch (RemoteException e) {} } diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index b616c1e..d813dab 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -16,6 +16,7 @@ package android.app; +import android.Manifest; import android.os.Binder; import android.os.IBinder; import android.util.ArrayMap; @@ -184,8 +185,10 @@ public class AppOpsManager { public static final int OP_MONITOR_LOCATION = 41; /** @hide Continually monitoring location data with a relatively high power request. */ public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42; + /** @hide Retrieve current usage stats via {@link UsageStatsManager}. */ + public static final int OP_GET_USAGE_STATS = 43; /** @hide */ - public static final int _NUM_OP = 43; + public static final int _NUM_OP = 44; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = @@ -252,6 +255,7 @@ public class AppOpsManager { OP_WAKE_LOCK, OP_COARSE_LOCATION, OP_COARSE_LOCATION, + OP_GET_USAGE_STATS, }; /** @@ -302,6 +306,7 @@ public class AppOpsManager { null, OPSTR_MONITOR_LOCATION, OPSTR_MONITOR_HIGH_POWER_LOCATION, + null, }; /** @@ -352,6 +357,7 @@ public class AppOpsManager { "WAKE_LOCK", "MONITOR_LOCATION", "MONITOR_HIGH_POWER_LOCATION", + "GET_USAGE_STATS" }; /** @@ -402,6 +408,7 @@ public class AppOpsManager { android.Manifest.permission.WAKE_LOCK, null, // no permission for generic location monitoring null, // no permission for high power location monitoring + android.Manifest.permission.PACKAGE_USAGE_STATS, }; /** @@ -451,6 +458,7 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, + AppOpsManager.MODE_IGNORED, // OP_GET_USAGE_STATS }; /** @@ -504,6 +512,7 @@ public class AppOpsManager { false, false, false, + false, }; private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>(); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index c621696..801182d 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -16,6 +16,8 @@ package android.app; +import android.net.wifi.IWifiScanner; +import android.net.wifi.WifiScanner; import android.os.Build; import com.android.internal.policy.PolicyManager; @@ -589,6 +591,13 @@ class ContextImpl extends Context { return new WifiP2pManager(service); }}); + registerService(WIFI_SCANNING_SERVICE, new ServiceFetcher() { + public Object createService(ContextImpl ctx) { + IBinder b = ServiceManager.getService(WIFI_SCANNING_SERVICE); + IWifiScanner service = IWifiScanner.Stub.asInterface(b); + return new WifiScanner(ctx.getOuterContext(), service); + }}); + registerService(WINDOW_SERVICE, new ServiceFetcher() { Display mDefaultDisplay; public Object getService(ContextImpl ctx) { @@ -669,6 +678,11 @@ class ContextImpl extends Context { return new NetworkScoreManager(ctx); } }); + + registerService(USAGE_STATS_SERVICE, new ServiceFetcher() { + public Object createService(ContextImpl ctx) { + return new UsageStatsManager(ctx.getOuterContext()); + }}); } static ContextImpl getImpl(Context context) { diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 25a1493..bba6caf 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -17,7 +17,7 @@ package android.app; import com.android.internal.R; -import com.android.internal.util.LegacyNotificationUtil; +import com.android.internal.util.NotificationColorUtil; import android.annotation.IntDef; import android.content.Context; @@ -28,6 +28,7 @@ import android.graphics.PorterDuff; import android.media.AudioManager; import android.net.Uri; import android.os.BadParcelableException; +import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -420,6 +421,21 @@ public class Notification implements Parcelable @Priority public int priority; + /** + * Accent color (an ARGB integer like the constants in {@link android.graphics.Color}) + * to be applied by the standard Style templates when presenting this notification. + * + * The current template design constructs a colorful header image by overlaying the + * {@link #icon} image (stenciled in white) atop a field of this color. Alpha components are + * ignored. + */ + public int color = COLOR_DEFAULT; + + /** + * Special value of {@link #color} telling the system not to decorate this notification with + * any special color but instead use default colors when presenting this notification. + */ + public static final int COLOR_DEFAULT = 0; // AKA Color.TRANSPARENT /** * Sphere of visibility of this notification, which affects how and when the SystemUI reveals @@ -877,6 +893,8 @@ public class Notification implements Parcelable if (parcel.readInt() != 0) { publicVersion = Notification.CREATOR.createFromParcel(parcel); } + + color = parcel.readInt(); } @Override @@ -968,6 +986,8 @@ public class Notification implements Parcelable this.publicVersion.cloneInto(that.publicVersion, heavy); } + that.color = this.color; + if (!heavy) { that.lightenPayload(); // will clean out extras } @@ -1110,6 +1130,8 @@ public class Notification implements Parcelable } else { parcel.writeInt(0); } + + parcel.writeInt(color); } /** @@ -1218,6 +1240,7 @@ public class Notification implements Parcelable sb.append(Integer.toHexString(this.defaults)); sb.append(" flags=0x"); sb.append(Integer.toHexString(this.flags)); + sb.append(String.format(" color=0x%08x", this.color)); sb.append(" category="); sb.append(this.category); if (actions != null) { sb.append(" "); @@ -1309,9 +1332,10 @@ public class Notification implements Parcelable private boolean mShowWhen = true; private int mVisibility = VISIBILITY_PRIVATE; private Notification mPublicVersion = null; - private boolean mQuantumTheme; - private final LegacyNotificationUtil mLegacyNotificationUtil; + private final NotificationColorUtil mColorUtil; private ArrayList<String> mPeople; + private boolean mPreQuantum; + private int mColor = COLOR_DEFAULT; /** * Constructs a new Builder with the defaults: @@ -1341,12 +1365,8 @@ public class Notification implements Parcelable mPriority = PRIORITY_DEFAULT; mPeople = new ArrayList<String>(); - // TODO: Decide on targetSdk from calling app whether to use quantum theme. - mQuantumTheme = true; - - // TODO: Decide on targetSdk from calling app whether to instantiate the processor at - // all. - mLegacyNotificationUtil = LegacyNotificationUtil.getInstance(); + mPreQuantum = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.L; + mColorUtil = NotificationColorUtil.getInstance(); } /** @@ -1853,29 +1873,38 @@ public class Notification implements Parcelable } } + /** + * Sets {@link Notification#color}. + * + * @param argb The accent color to use + * + * @return The same Builder. + */ + public Builder setColor(int argb) { + mColor = argb; + return this; + } + private RemoteViews applyStandardTemplate(int resId, boolean fitIn1U) { RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId); boolean showLine3 = false; boolean showLine2 = false; int smallIconImageViewId = R.id.icon; - if (!mQuantumTheme && mPriority < PRIORITY_LOW) { - contentView.setInt(R.id.icon, - "setBackgroundResource", R.drawable.notification_template_icon_low_bg); - contentView.setInt(R.id.status_bar_latest_event_content, - "setBackgroundResource", R.drawable.notification_bg_low); + if (mPriority < PRIORITY_LOW) { + // TODO: Low priority presentation } if (mLargeIcon != null) { contentView.setImageViewBitmap(R.id.icon, mLargeIcon); - processLegacyLargeIcon(mLargeIcon, contentView); + processLargeIcon(mLargeIcon, contentView); smallIconImageViewId = R.id.right_icon; } if (mSmallIcon != 0) { contentView.setImageViewResource(smallIconImageViewId, mSmallIcon); contentView.setViewVisibility(smallIconImageViewId, View.VISIBLE); if (mLargeIcon != null) { - processLegacySmallIcon(mSmallIcon, smallIconImageViewId, contentView); + processSmallRightIcon(mSmallIcon, smallIconImageViewId, contentView); } else { - processLegacyLargeIcon(mSmallIcon, contentView); + processSmallIconAsLarge(mSmallIcon, contentView); } } else { @@ -2035,12 +2064,12 @@ public class Notification implements Parcelable * doesn't create quantum notifications by itself) app. */ private boolean isLegacy() { - return mLegacyNotificationUtil != null; + return mColorUtil != null; } private void processLegacyAction(Action action, RemoteViews button) { if (isLegacy()) { - if (mLegacyNotificationUtil.isGrayscale(mContext, action.icon)) { + if (mColorUtil.isGrayscale(mContext, action.icon)) { button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0, mContext.getResources().getColor( R.color.notification_action_legacy_color_filter), @@ -2051,45 +2080,68 @@ public class Notification implements Parcelable private CharSequence processLegacyText(CharSequence charSequence) { if (isLegacy()) { - return mLegacyNotificationUtil.invertCharSequenceColors(charSequence); + return mColorUtil.invertCharSequenceColors(charSequence); } else { return charSequence; } } - private void processLegacyLargeIcon(int largeIconId, RemoteViews contentView) { - if (isLegacy()) { - processLegacyLargeIcon( - mLegacyNotificationUtil.isGrayscale(mContext, largeIconId), - contentView); + /** + * Apply any necessary background to smallIcons being used in the largeIcon spot. + */ + private void processSmallIconAsLarge(int largeIconId, RemoteViews contentView) { + if (!isLegacy() || mColorUtil.isGrayscale(mContext, largeIconId)) { + applyLargeIconBackground(contentView); } } - private void processLegacyLargeIcon(Bitmap largeIcon, RemoteViews contentView) { - if (isLegacy()) { - processLegacyLargeIcon( - mLegacyNotificationUtil.isGrayscale(largeIcon), - contentView); + /** + * Apply any necessary background to a largeIcon if it's a fake smallIcon (that is, + * if it's grayscale). + */ + // TODO: also check bounds, transparency, that sort of thing. + private void processLargeIcon(Bitmap largeIcon, RemoteViews contentView) { + if (!isLegacy() || mColorUtil.isGrayscale(largeIcon)) { + applyLargeIconBackground(contentView); } } - private void processLegacyLargeIcon(boolean isGrayscale, RemoteViews contentView) { - if (isLegacy() && isGrayscale) { - contentView.setInt(R.id.icon, "setBackgroundResource", - R.drawable.notification_icon_legacy_bg_inset); - } + /** + * Add a colored circle behind the largeIcon slot. + */ + private void applyLargeIconBackground(RemoteViews contentView) { + contentView.setInt(R.id.icon, "setBackgroundResource", + R.drawable.notification_icon_legacy_bg_inset); + + contentView.setDrawableParameters( + R.id.icon, + true, + -1, + mColor, + PorterDuff.Mode.SRC_ATOP, + -1); } - private void processLegacySmallIcon(int smallIconDrawableId, int smallIconImageViewId, + /** + * Recolor small icons when used in the R.id.right_icon slot. + */ + private void processSmallRightIcon(int smallIconDrawableId, int smallIconImageViewId, RemoteViews contentView) { - if (isLegacy()) { - if (mLegacyNotificationUtil.isGrayscale(mContext, smallIconDrawableId)) { - contentView.setDrawableParameters(smallIconImageViewId, false, -1, - mContext.getResources().getColor( - R.color.notification_action_legacy_color_filter), - PorterDuff.Mode.MULTIPLY, -1); - } + if (!isLegacy() || mColorUtil.isGrayscale(mContext, smallIconDrawableId)) { + contentView.setDrawableParameters(smallIconImageViewId, false, -1, + mContext.getResources().getColor( + R.color.notification_action_legacy_color_filter), + PorterDuff.Mode.MULTIPLY, -1); + } + } + + private int resolveColor() { + if (mColor == COLOR_DEFAULT) { + mColor = mContext.getResources().getColor(R.color.notification_icon_bg_color); + } else { + mColor |= 0xFF000000; // no alpha for custom colors } + return mColor; } /** @@ -2102,6 +2154,9 @@ public class Notification implements Parcelable n.icon = mSmallIcon; n.iconLevel = mSmallIconLevel; n.number = mNumber; + + n.color = resolveColor(); + n.contentView = makeContentView(); n.contentIntent = mContentIntent; n.deleteIntent = mDeleteIntent; @@ -2207,45 +2262,31 @@ public class Notification implements Parcelable private int getBaseLayoutResource() { - return mQuantumTheme - ? R.layout.notification_template_quantum_base - : R.layout.notification_template_base; + return R.layout.notification_template_quantum_base; } private int getBigBaseLayoutResource() { - return mQuantumTheme - ? R.layout.notification_template_quantum_big_base - : R.layout.notification_template_big_base; + return R.layout.notification_template_quantum_big_base; } private int getBigPictureLayoutResource() { - return mQuantumTheme - ? R.layout.notification_template_quantum_big_picture - : R.layout.notification_template_big_picture; + return R.layout.notification_template_quantum_big_picture; } private int getBigTextLayoutResource() { - return mQuantumTheme - ? R.layout.notification_template_quantum_big_text - : R.layout.notification_template_big_text; + return R.layout.notification_template_quantum_big_text; } private int getInboxLayoutResource() { - return mQuantumTheme - ? R.layout.notification_template_quantum_inbox - : R.layout.notification_template_inbox; + return R.layout.notification_template_quantum_inbox; } private int getActionLayoutResource() { - return mQuantumTheme - ? R.layout.notification_quantum_action - : R.layout.notification_action; + return R.layout.notification_quantum_action; } private int getActionTombstoneLayoutResource() { - return mQuantumTheme - ? R.layout.notification_quantum_action_tombstone - : R.layout.notification_action_tombstone; + return R.layout.notification_quantum_action_tombstone; } } diff --git a/core/java/android/app/UsageStats.aidl b/core/java/android/app/UsageStats.aidl new file mode 100644 index 0000000..7dee70a --- /dev/null +++ b/core/java/android/app/UsageStats.aidl @@ -0,0 +1,20 @@ +/** + * 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. + */ + +package android.app; + +parcelable UsageStats; +parcelable UsageStats.PackageStats; diff --git a/core/java/android/app/UsageStats.java b/core/java/android/app/UsageStats.java new file mode 100644 index 0000000..0aeba59 --- /dev/null +++ b/core/java/android/app/UsageStats.java @@ -0,0 +1,406 @@ +/* + * 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. + */ + +package android.app; + +import android.content.res.Configuration; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.SystemClock; +import android.util.ArrayMap; + +import java.util.Map; + +/** + * Snapshot of current usage stats data. + * @hide + */ +public class UsageStats implements Parcelable { + /** @hide */ + public final ArrayMap<String, PackageStats> mPackages = new ArrayMap<String, PackageStats>(); + /** @hide */ + public final ArrayMap<Configuration, ConfigurationStats> mConfigurations + = new ArrayMap<Configuration, ConfigurationStats>(); + + public static class PackageStats implements Parcelable { + private final String mPackageName; + private int mLaunchCount; + private long mUsageTime; + private long mResumedTime; + + /** @hide */ + public final ArrayMap<String, Long> componentResumeTimes; + + public static final Parcelable.Creator<PackageStats> CREATOR + = new Parcelable.Creator<PackageStats>() { + public PackageStats createFromParcel(Parcel in) { + return new PackageStats(in); + } + + public PackageStats[] newArray(int size) { + return new PackageStats[size]; + } + }; + + public String toString() { + return "PackageStats{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + mPackageName + "}"; + } + + /** @hide */ + public PackageStats(String pkgName) { + mPackageName = pkgName; + componentResumeTimes = new ArrayMap<String, Long>(); + } + + /** @hide */ + public PackageStats(String pkgName, int count, long time, Map<String, Long> lastResumeTimes) { + mPackageName = pkgName; + mLaunchCount = count; + mUsageTime = time; + componentResumeTimes = new ArrayMap<String, Long>(); + componentResumeTimes.putAll(lastResumeTimes); + } + + /** @hide */ + public PackageStats(Parcel source) { + mPackageName = source.readString(); + mLaunchCount = source.readInt(); + mUsageTime = source.readLong(); + final int N = source.readInt(); + componentResumeTimes = new ArrayMap<String, Long>(N); + for (int i = 0; i < N; i++) { + String component = source.readString(); + long lastResumeTime = source.readLong(); + componentResumeTimes.put(component, lastResumeTime); + } + } + + /** @hide */ + public PackageStats(PackageStats pStats) { + mPackageName = pStats.mPackageName; + mLaunchCount = pStats.mLaunchCount; + mUsageTime = pStats.mUsageTime; + componentResumeTimes = new ArrayMap<String, Long>(pStats.componentResumeTimes); + } + + /** @hide */ + public void resume(boolean launched) { + if (launched) { + mLaunchCount++; + } + mResumedTime = SystemClock.elapsedRealtime(); + } + + /** @hide */ + public void pause() { + if (mResumedTime > 0) { + mUsageTime += SystemClock.elapsedRealtime() - mResumedTime; + } + mResumedTime = 0; + } + + public final String getPackageName() { + return mPackageName; + } + + public final long getUsageTime(long elapsedRealtime) { + return mUsageTime + (mResumedTime > 0 ? (elapsedRealtime- mResumedTime) : 0); + } + + public final int getLaunchCount() { + return mLaunchCount; + } + + /** @hide */ + public boolean clearUsageTimes() { + mLaunchCount = 0; + mUsageTime = 0; + return mResumedTime <= 0 && componentResumeTimes.isEmpty(); + } + + public final int describeContents() { + return 0; + } + + public final void writeToParcel(Parcel dest, int parcelableFlags) { + writeToParcel(dest, parcelableFlags, 0); + } + + final void writeToParcel(Parcel dest, int parcelableFlags, long elapsedRealtime) { + dest.writeString(mPackageName); + dest.writeInt(mLaunchCount); + dest.writeLong(elapsedRealtime > 0 ? getUsageTime(elapsedRealtime) : mUsageTime); + dest.writeInt(componentResumeTimes.size()); + for (Map.Entry<String, Long> ent : componentResumeTimes.entrySet()) { + dest.writeString(ent.getKey()); + dest.writeLong(ent.getValue()); + } + } + + /** @hide */ + public void writeExtendedToParcel(Parcel dest, int parcelableFlags) { + } + } + + public static class ConfigurationStats implements Parcelable { + private final Configuration mConfiguration; + private long mLastUsedTime; + private int mUsageCount; + private long mUsageTime; + private long mStartedTime; + + public static final Parcelable.Creator<ConfigurationStats> CREATOR + = new Parcelable.Creator<ConfigurationStats>() { + public ConfigurationStats createFromParcel(Parcel in) { + return new ConfigurationStats(in); + } + + public ConfigurationStats[] newArray(int size) { + return new ConfigurationStats[size]; + } + }; + + public String toString() { + return "ConfigurationStats{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + mConfiguration + "}"; + } + + /** @hide */ + public ConfigurationStats(Configuration config) { + mConfiguration = config; + } + + /** @hide */ + public ConfigurationStats(Parcel source) { + mConfiguration = Configuration.CREATOR.createFromParcel(source); + mLastUsedTime = source.readLong(); + mUsageCount = source.readInt(); + mUsageTime = source.readLong(); + } + + /** @hide */ + public ConfigurationStats(ConfigurationStats pStats) { + mConfiguration = pStats.mConfiguration; + mLastUsedTime = pStats.mLastUsedTime; + mUsageCount = pStats.mUsageCount; + mUsageTime = pStats.mUsageTime; + } + + public final Configuration getConfiguration() { + return mConfiguration; + } + + public final long getLastUsedTime() { + return mLastUsedTime; + } + + public final long getUsageTime(long elapsedRealtime) { + return mUsageTime + (mStartedTime > 0 ? (elapsedRealtime- mStartedTime) : 0); + } + + public final int getUsageCount() { + return mUsageCount; + } + + /** @hide */ + public void start() { + mLastUsedTime = System.currentTimeMillis(); + mUsageCount++; + mStartedTime = SystemClock.elapsedRealtime(); + } + + /** @hide */ + public void stop() { + if (mStartedTime > 0) { + mUsageTime += SystemClock.elapsedRealtime() - mStartedTime; + } + mStartedTime = 0; + } + + /** @hide */ + public boolean clearUsageTimes() { + mUsageCount = 0; + mUsageTime = 0; + return mLastUsedTime == 0 && mStartedTime <= 0; + } + + public final int describeContents() { + return 0; + } + + public final void writeToParcel(Parcel dest, int parcelableFlags) { + writeToParcel(dest, parcelableFlags, 0); + } + + final void writeToParcel(Parcel dest, int parcelableFlags, long elapsedRealtime) { + mConfiguration.writeToParcel(dest, parcelableFlags); + dest.writeLong(mLastUsedTime); + dest.writeInt(mUsageCount); + dest.writeLong(elapsedRealtime > 0 ? getUsageTime(elapsedRealtime) : mUsageTime); + } + + /** @hide */ + public void writeExtendedToParcel(Parcel dest, int parcelableFlags) { + } + } + + /** @hide */ + public UsageStats() { + } + + /** @hide */ + public UsageStats(Parcel source, boolean extended) { + int N = source.readInt(); + for (int i=0; i<N; i++) { + PackageStats pkg = extended ? onNewPackageStats(source) : new PackageStats(source); + mPackages.put(pkg.getPackageName(), pkg); + } + N = source.readInt(); + for (int i=0; i<N; i++) { + ConfigurationStats config = extended ? onNewConfigurationStats(source) + : new ConfigurationStats(source); + mConfigurations.put(config.getConfiguration(), config); + } + } + + public int getPackageStatsCount() { + return mPackages.size(); + } + + public PackageStats getPackageStatsAt(int index) { + return mPackages.valueAt(index); + } + + public PackageStats getPackageStats(String pkgName) { + return mPackages.get(pkgName); + } + + /** @hide */ + public PackageStats getOrCreatePackageStats(String pkgName) { + PackageStats ps = mPackages.get(pkgName); + if (ps == null) { + ps = onNewPackageStats(pkgName); + mPackages.put(pkgName, ps); + } + return ps; + } + + public int getConfigurationStatsCount() { + return mConfigurations.size(); + } + + public ConfigurationStats getConfigurationStatsAt(int index) { + return mConfigurations.valueAt(index); + } + + public ConfigurationStats getConfigurationStats(Configuration config) { + return mConfigurations.get(config); + } + + /** @hide */ + public ConfigurationStats getOrCreateConfigurationStats(Configuration config) { + ConfigurationStats cs = mConfigurations.get(config); + if (cs == null) { + cs = onNewConfigurationStats(config); + mConfigurations.put(config, cs); + } + return cs; + } + + /** @hide */ + public void clearUsageTimes() { + for (int i=mPackages.size()-1; i>=0; i--) { + if (mPackages.valueAt(i).clearUsageTimes()) { + mPackages.removeAt(i); + } + } + for (int i=mConfigurations.size()-1; i>=0; i--) { + if (mConfigurations.valueAt(i).clearUsageTimes()) { + mConfigurations.removeAt(i); + } + } + } + + /** @hide */ + public PackageStats onNewPackageStats(String pkgName) { + return new PackageStats(pkgName); + } + + /** @hide */ + public PackageStats onNewPackageStats(Parcel source) { + return new PackageStats(source); + } + + /** @hide */ + public ConfigurationStats onNewConfigurationStats(Configuration config) { + return new ConfigurationStats(config); + } + + /** @hide */ + public ConfigurationStats onNewConfigurationStats(Parcel source) { + return new ConfigurationStats(source); + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int parcelableFlags) { + writeToParcelInner(dest, parcelableFlags, false); + } + + /** @hide */ + public void writeExtendedToParcel(Parcel dest, int parcelableFlags) { + writeToParcelInner(dest, parcelableFlags, true); + } + + private void writeToParcelInner(Parcel dest, int parcelableFlags, boolean extended) { + final long elapsedRealtime = SystemClock.elapsedRealtime(); + + int N = mPackages.size(); + dest.writeInt(N); + for (int i=0; i<N; i++) { + PackageStats ps = mPackages.valueAt(i); + ps.writeToParcel(dest, parcelableFlags, elapsedRealtime); + if (extended) { + ps.writeExtendedToParcel(dest, parcelableFlags); + } + } + N = mConfigurations.size(); + dest.writeInt(N); + for (int i=0; i<N; i++) { + ConfigurationStats cs = mConfigurations.valueAt(i); + cs.writeToParcel(dest, parcelableFlags, elapsedRealtime); + if (extended) { + cs.writeExtendedToParcel(dest, parcelableFlags); + } + } + } + + public static final Parcelable.Creator<UsageStats> CREATOR + = new Parcelable.Creator<UsageStats>() { + public UsageStats createFromParcel(Parcel in) { + return new UsageStats(in, false); + } + + public UsageStats[] newArray(int size) { + return new UsageStats[size]; + } + }; +} diff --git a/core/java/android/app/UsageStatsManager.java b/core/java/android/app/UsageStatsManager.java new file mode 100644 index 0000000..fbf9c3b --- /dev/null +++ b/core/java/android/app/UsageStatsManager.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +package android.app; + +import android.content.Context; +import android.os.ParcelableParcel; +import android.os.RemoteException; +import android.os.ServiceManager; +import com.android.internal.app.IUsageStats; + +/** + * Access to usage stats data. + * @hide + */ +public class UsageStatsManager { + final Context mContext; + final IUsageStats mService; + + /** @hide */ + public UsageStatsManager(Context context) { + mContext = context; + mService = IUsageStats.Stub.asInterface(ServiceManager.getService( + Context.USAGE_STATS_SERVICE)); + } + + public UsageStats getCurrentStats() { + try { + ParcelableParcel in = mService.getCurrentStats(mContext.getOpPackageName()); + if (in != null) { + return new UsageStats(in.getParcel(), false); + } + } catch (RemoteException e) { + // About to die. + } + return new UsageStats(); + } +} diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index b24b932..58049fd 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -16,8 +16,6 @@ package android.app.admin; -import org.xmlpull.v1.XmlPullParserException; - import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.ComponentName; @@ -39,6 +37,8 @@ import android.util.Log; import com.android.org.conscrypt.TrustedCertificateStore; +import org.xmlpull.v1.XmlPullParserException; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.InetSocketAddress; @@ -359,8 +359,8 @@ public class DevicePolicyManager { } /** - * Retrieve the current minimum password quality for all admins - * or a particular one. + * Retrieve the current minimum password quality for all admins of this user + * and its profiles or a particular one. * @param admin The name of the admin component to check, or null to aggregate * all admins. */ @@ -412,8 +412,8 @@ public class DevicePolicyManager { } /** - * Retrieve the current minimum password length for all admins - * or a particular one. + * Retrieve the current minimum password length for all admins of this + * user and its profiles or a particular one. * @param admin The name of the admin component to check, or null to aggregate * all admins. */ @@ -467,8 +467,9 @@ public class DevicePolicyManager { /** * Retrieve the current number of upper case letters required in the - * password for all admins or a particular one. This is the same value as - * set by {#link {@link #setPasswordMinimumUpperCase(ComponentName, int)} + * password for all admins of this user and its profiles or a particular one. + * This is the same value as set by + * {#link {@link #setPasswordMinimumUpperCase(ComponentName, int)} * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * @@ -527,8 +528,9 @@ public class DevicePolicyManager { /** * Retrieve the current number of lower case letters required in the - * password for all admins or a particular one. This is the same value as - * set by {#link {@link #setPasswordMinimumLowerCase(ComponentName, int)} + * password for all admins of this user and its profiles or a particular one. + * This is the same value as set by + * {#link {@link #setPasswordMinimumLowerCase(ComponentName, int)} * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * @@ -644,8 +646,9 @@ public class DevicePolicyManager { /** * Retrieve the current number of numerical digits required in the password - * for all admins or a particular one. This is the same value as - * set by {#link {@link #setPasswordMinimumNumeric(ComponentName, int)} + * for all admins of this user and its profiles or a particular one. + * This is the same value as set by + * {#link {@link #setPasswordMinimumNumeric(ComponentName, int)} * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * @@ -760,8 +763,9 @@ public class DevicePolicyManager { /** * Retrieve the current number of non-letter characters required in the - * password for all admins or a particular one. This is the same value as - * set by {#link {@link #setPasswordMinimumNonLetter(ComponentName, int)} + * password for all admins of this user and its profiles or a particular one. + * This is the same value as set by + * {#link {@link #setPasswordMinimumNonLetter(ComponentName, int)} * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * @@ -868,9 +872,10 @@ public class DevicePolicyManager { /** * Get the current password expiration time for the given admin or an aggregate of - * all admins if admin is null. If the password is expired, this will return the time since - * the password expired as a negative number. If admin is null, then a composite of all - * expiration timeouts is returned - which will be the minimum of all timeouts. + * all admins of this user and its profiles if admin is null. If the password is + * expired, this will return the time since the password expired as a negative number. + * If admin is null, then a composite of all expiration timeouts is returned + * - which will be the minimum of all timeouts. * * @param admin The name of the admin component to check, or null to aggregate all admins. * @return The password expiration time, in ms. @@ -887,8 +892,8 @@ public class DevicePolicyManager { } /** - * Retrieve the current password history length for all admins - * or a particular one. + * Retrieve the current password history length for all admins of this + * user and its profiles or a particular one. * @param admin The name of the admin component to check, or null to aggregate * all admins. * @return The length of the password history @@ -923,14 +928,13 @@ public class DevicePolicyManager { /** * Determine whether the current password the user has set is sufficient * to meet the policy requirements (quality, minimum length) that have been - * requested. + * requested by the admins of this user and its profiles. * * <p>The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call * this method; if it has not, a security exception will be thrown. * - * @return Returns true if the password meets the current requirements, - * else false. + * @return Returns true if the password meets the current requirements, else false. */ public boolean isActivePasswordSufficient() { if (mService != null) { @@ -993,7 +997,7 @@ public class DevicePolicyManager { /** * Retrieve the current maximum number of login attempts that are allowed - * before the device wipes itself, for all admins + * before the device wipes itself, for all admins of this user and its profiles * or a particular one. * @param admin The name of the admin component to check, or null to aggregate * all admins. @@ -1037,6 +1041,8 @@ public class DevicePolicyManager { * {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} to be able to call * this method; if it has not, a security exception will be thrown. * + * Can not be called from a managed profile. + * * @param password The new password for the user. * @param flags May be 0 or {@link #RESET_PASSWORD_REQUIRE_ENTRY}. * @return Returns true if the password was applied, or false if it is @@ -1077,8 +1083,8 @@ public class DevicePolicyManager { } /** - * Retrieve the current maximum time to unlock for all admins - * or a particular one. + * Retrieve the current maximum time to unlock for all admins of this user + * and its profiles or a particular one. * @param admin The name of the admin component to check, or null to aggregate * all admins. */ @@ -2062,6 +2068,28 @@ public class DevicePolicyManager { } /** + * Called by a profile owner to disable account management for a specific type of account. + * + * <p>The calling device admin must be a profile owner. If it is not, a + * security exception will be thrown. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param accountType For which account management is disabled or enabled. + * @param disabled The boolean indicating that account management will be disabled (true) or + * enabled (false). + */ + public void setAccountManagementDisabled(ComponentName admin, String accountType, + boolean disabled) { + if (mService != null) { + try { + mService.setAccountManagementDisabled(admin, accountType, disabled); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + } + + /** * Called by profile or device owner to re-enable system apps by intent that were disabled * by default when the managed profile was created. This should only be called from a profile * or device owner running within a managed profile. @@ -2069,7 +2097,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param intent An intent matching the app(s) to be installed. All apps that resolve for this * intent will be re-enabled in the current profile. - * @returns int The number of activities that matched the intent and were installed. + * @return int The number of activities that matched the intent and were installed. */ public int enableSystemApp(ComponentName admin, Intent intent) { if (mService != null) { @@ -2081,4 +2109,73 @@ public class DevicePolicyManager { } return 0; } + + /** + * Gets the array of accounts for which account management is disabled by the profile owner. + * + * <p> Account management can be disabled/enabled by calling + * {@link #setAccountManagementDisabled}. + * + * @return a list of account types for which account management has been disabled. + * + * @see #setAccountManagementDisabled + */ + public String[] getAccountTypesWithManagementDisabled() { + if (mService != null) { + try { + return mService.getAccountTypesWithManagementDisabled(); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + + return null; + } + + /** + * Sets which components may enter lock task mode. + * + * This function can only be called by the device owner or the profile owner. + * @param components The list of components allowed to enter lock task mode + */ + public void setLockTaskComponents(ComponentName[] components) throws SecurityException { + if (mService != null) { + try { + mService.setLockTaskComponents(components); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + } + + /** + * This function returns the list of components allowed to start the lock task mode. + * @hide + */ + public ComponentName[] getLockTaskComponents() { + if (mService != null) { + try { + return mService.getLockTaskComponents(); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + return null; + } + + /** + * This function lets the caller know whether the given component is allowed to start the + * lock task mode. + * @param component The component to check + */ + public boolean isLockTaskPermitted(ComponentName component) { + if (mService != null) { + try { + return mService.isLockTaskPermitted(component); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + return false; + } } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index b30f1b9..03ced0f 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -126,4 +126,11 @@ interface IDevicePolicyManager { void enableSystemApp(in ComponentName admin, in String packageName); int enableSystemAppWithIntent(in ComponentName admin, in Intent intent); + + void setAccountManagementDisabled(in ComponentName who, in String accountType, in boolean disabled); + String[] getAccountTypesWithManagementDisabled(); + + void setLockTaskComponents(in ComponentName[] components); + ComponentName[] getLockTaskComponents(); + boolean isLockTaskPermitted(in ComponentName component); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 7c625bd..a059e48 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1982,6 +1982,7 @@ public abstract class Context { WIFI_SERVICE, WIFI_HOTSPOT_SERVICE, WIFI_P2P_SERVICE, + WIFI_SCANNING_SERVICE, NSD_SERVICE, AUDIO_SERVICE, MEDIA_ROUTER_SERVICE, @@ -2054,6 +2055,9 @@ public abstract class Context { * <dt> {@link #WIFI_SERVICE} ("wifi") * <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of * Wi-Fi connectivity. + * <dt> {@link #WIFI_P2P_SERVICE} ("wifip2p") + * <dd> A {@link android.net.wifi.p2p.WifiP2pManager WifiP2pManager} for management of + * Wi-Fi Direct connectivity. * <dt> {@link #INPUT_METHOD_SERVICE} ("input_method") * <dd> An {@link android.view.inputmethod.InputMethodManager InputMethodManager} * for management of input methods. @@ -2357,6 +2361,16 @@ public abstract class Context { /** * Use with {@link #getSystemService} to retrieve a {@link + * android.net.wifi.WifiScanner} for scanning the wifi universe + * + * @see #getSystemService + * @see android.net.wifi.WifiScanner + * @hide + */ + public static final String WIFI_SCANNING_SERVICE = "wifiscanner"; + + /** + * Use with {@link #getSystemService} to retrieve a {@link * android.net.nsd.NsdManager} for handling management of network service * discovery * @@ -2669,6 +2683,16 @@ public abstract class Context { public static final String NETWORK_SCORE_SERVICE = "network_score"; /** + * Use with {@link #getSystemService} to retrieve a {@link + * android.app.UsageStatsManager} for interacting with the status bar. + * + * @see #getSystemService + * @see android.app.UsageStatsManager + * @hide + */ + public static final String USAGE_STATS_SERVICE = "usagestats"; + + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. * diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java index a9a62a7..9ba45ca 100644 --- a/core/java/android/content/SyncRequest.java +++ b/core/java/android/content/SyncRequest.java @@ -473,7 +473,7 @@ public class SyncRequest implements Parcelable { * SyncRequest.Builder builder = * new SyncRequest.Builder() * .setSyncAdapter(dummyAccount, dummyProvider) - * .syncOnce(5 * MINUTES_IN_SECS); + * .syncOnce(); * * for (String syncData : syncItems) { * Bundle extras = new Bundle(); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 1a003ff..eb2c11f 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -936,13 +936,21 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device has at least one camera pointing in - * some direction. + * some direction, or can support an external camera being connected to it. */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_CAMERA_ANY = "android.hardware.camera.any"; /** * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device can support having an external camera connected to it. + * The external camera may not always be connected or available to applications to use. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_CAMERA_EXTERNAL = "android.hardware.camera.external"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device's camera supports flash. */ @SdkConstant(SdkConstantType.FEATURE) @@ -1083,6 +1091,13 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device includes a heart rate monitor. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device has a telephony radio with data * communication support. */ diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index d80ab7b..ff96c51 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -3600,10 +3600,13 @@ public class PackageParser { // For use by the package manager to keep track of the path to the // file an app came from. public String mScanPath; - - // For use by package manager to keep track of where it has done dexopt. - public boolean mDidDexOpt; - + + // For use by package manager to keep track of where it needs to do dexopt. + public boolean mDexOptNeeded = true; + + // For use by package manager to keep track of when a package was last used. + public long mLastPackageUsageTimeInMills; + // // User set enabled state. // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; // diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 28309d7..5f2af8c 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -1277,20 +1277,6 @@ public final class CameraCharacteristics extends CameraMetadata { new Key<Integer>("android.sensor.orientation", int.class); /** - * <p>The number of input samples for each dimension of - * {@link CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP android.sensor.profileHueSatMap}.</p> - * <p>The number of input samples for the hue, saturation, and value - * dimension of {@link CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP android.sensor.profileHueSatMap}. The order of the - * dimensions given is hue, saturation, value; where hue is the 0th - * element.</p> - * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> - * - * @see CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP - */ - public static final Key<int[]> SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS = - new Key<int[]>("android.sensor.profileHueSatMapDimensions", int[].class); - - /** * <p>Optional. Defaults to [OFF]. Lists the supported test * pattern modes for {@link CaptureRequest#SENSOR_TEST_PATTERN_MODE android.sensor.testPatternMode}.</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 1d2d0e9..51ea447 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -1906,36 +1906,6 @@ public final class CaptureResult extends CameraMetadata { new Key<Rational[]>("android.sensor.neutralColorPoint", Rational[].class); /** - * <p>A mapping containing a hue shift, saturation scale, and value scale - * for each pixel.</p> - * <p>hue_samples, saturation_samples, and value_samples are given in - * {@link CameraCharacteristics#SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS android.sensor.profileHueSatMapDimensions}.</p> - * <p>Each entry of this map contains three floats corresponding to the - * hue shift, saturation scale, and value scale, respectively; where the - * hue shift has the lowest index. The map entries are stored in the tag - * in nested loop order, with the value divisions in the outer loop, the - * hue divisions in the middle loop, and the saturation divisions in the - * inner loop. All zero input saturation entries are required to have a - * value scale factor of 1.0.</p> - * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> - * - * @see CameraCharacteristics#SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS - */ - public static final Key<float[]> SENSOR_PROFILE_HUE_SAT_MAP = - new Key<float[]>("android.sensor.profileHueSatMap", float[].class); - - /** - * <p>A list of x,y samples defining a tone-mapping curve for gamma adjustment.</p> - * <p>This tag contains a default tone curve that can be applied while - * processing the image as a starting point for user adjustments. - * The curve is specified as a list of value pairs in linear gamma. - * The curve is interpolated using a cubic spline.</p> - * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> - */ - public static final Key<float[]> SENSOR_PROFILE_TONE_CURVE = - new Key<float[]>("android.sensor.profileToneCurve", float[].class); - - /** * <p>The worst-case divergence between Bayer green channels.</p> * <p>This value is an estimate of the worst case split between the * Bayer green channels in the red and blue rows in the sensor color diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java index 8437228..ed223d1 100644 --- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java @@ -36,6 +36,7 @@ import android.view.MotionEvent; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.InputMethodSession; +import android.view.inputmethod.CursorAnchorInfo; class IInputMethodSessionWrapper extends IInputMethodSession.Stub implements HandlerCaller.Callback { @@ -46,6 +47,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub private static final int DO_UPDATE_EXTRACTED_TEXT = 67; private static final int DO_UPDATE_SELECTION = 90; private static final int DO_UPDATE_CURSOR = 95; + private static final int DO_UPDATE_CURSOR_ANCHOR_INFO = 99; private static final int DO_APP_PRIVATE_COMMAND = 100; private static final int DO_TOGGLE_SOFT_INPUT = 105; private static final int DO_FINISH_SESSION = 110; @@ -108,6 +110,10 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub mInputMethodSession.updateCursor((Rect)msg.obj); return; } + case DO_UPDATE_CURSOR_ANCHOR_INFO: { + mInputMethodSession.updateCursorAnchorInfo((CursorAnchorInfo)msg.obj); + return; + } case DO_APP_PRIVATE_COMMAND: { SomeArgs args = (SomeArgs)msg.obj; mInputMethodSession.appPrivateCommand((String)args.arg1, @@ -181,6 +187,12 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub } @Override + public void updateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) { + mCaller.executeOrSendMessage( + mCaller.obtainMessageO(DO_UPDATE_CURSOR_ANCHOR_INFO, cursorAnchorInfo)); + } + + @Override public void appPrivateCommand(String action, Bundle data) { mCaller.executeOrSendMessage( mCaller.obtainMessageOO(DO_APP_PRIVATE_COMMAND, action, data)); diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index f6438b4..4bccaf1 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -51,6 +51,7 @@ import android.view.WindowManager; import android.view.WindowManager.BadTokenException; import android.view.animation.AnimationUtils; import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; @@ -545,6 +546,17 @@ public class InputMethodService extends AbstractInputMethodService { public void toggleSoftInput(int showFlags, int hideFlags) { InputMethodService.this.onToggleSoftInput(showFlags, hideFlags); } + + /** + * Call {@link InputMethodService#onUpdateCursorAnchorInfo + * InputMethodService.onUpdateCursorAnchorInfo()}. + */ + public void updateCursorAnchorInfo(CursorAnchorInfo info) { + if (!isEnabled()) { + return; + } + InputMethodService.this.onUpdateCursorAnchorInfo(info); + } } /** @@ -1717,6 +1729,17 @@ public class InputMethodService extends AbstractInputMethodService { } /** + * Called when the application has reported a new location of its text insertion point and + * characters in the composition string. This is only called if explicitly requested by the + * input method. The default implementation does nothing. + * @param cursorAnchorInfo The positional information of the text insertion point and the + * composition string. + */ + public void onUpdateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) { + // Intentionally empty + } + + /** * Update the cursor/anthor monitor mode. */ public void setCursorAnchorMonitorMode(int monitorMode) { diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 3da00b1..30d7043 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1307,14 +1307,13 @@ public class ConnectivityManager { * doing something unusual like general internal filtering this may be useful. On * a private network where the proxy is not accessible, you may break HTTP using this. * - * @param p The a {@link ProxyProperties} object defining the new global + * @param p The a {@link ProxyInfo} object defining the new global * HTTP proxy. A {@code null} value will clear the global HTTP proxy. * * <p>This method requires the call to hold the permission - * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. - * {@hide} + * android.Manifest.permission#CONNECTIVITY_INTERNAL. */ - public void setGlobalProxy(ProxyProperties p) { + public void setGlobalProxy(ProxyInfo p) { try { mService.setGlobalProxy(p); } catch (RemoteException e) { @@ -1324,14 +1323,13 @@ public class ConnectivityManager { /** * Retrieve any network-independent global HTTP proxy. * - * @return {@link ProxyProperties} for the current global HTTP proxy or {@code null} + * @return {@link ProxyInfo} for the current global HTTP proxy or {@code null} * if no global HTTP proxy is set. * * <p>This method requires the call to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. - * {@hide} */ - public ProxyProperties getGlobalProxy() { + public ProxyInfo getGlobalProxy() { try { return mService.getGlobalProxy(); } catch (RemoteException e) { @@ -1343,14 +1341,14 @@ public class ConnectivityManager { * Get the HTTP proxy settings for the current default network. Note that * if a global proxy is set, it will override any per-network setting. * - * @return the {@link ProxyProperties} for the current HTTP proxy, or {@code null} if no + * @return the {@link ProxyInfo} for the current HTTP proxy, or {@code null} if no * HTTP proxy is active. * * <p>This method requires the call to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ - public ProxyProperties getProxy() { + public ProxyInfo getProxy() { try { return mService.getProxy(); } catch (RemoteException e) { diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 381a817..d53a856 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -21,7 +21,7 @@ import android.net.LinkProperties; import android.net.NetworkInfo; import android.net.NetworkQuotaInfo; import android.net.NetworkState; -import android.net.ProxyProperties; +import android.net.ProxyInfo; import android.os.IBinder; import android.os.Messenger; import android.os.ParcelFileDescriptor; @@ -107,11 +107,11 @@ interface IConnectivityManager void reportInetCondition(int networkType, int percentage); - ProxyProperties getGlobalProxy(); + ProxyInfo getGlobalProxy(); - void setGlobalProxy(in ProxyProperties p); + void setGlobalProxy(in ProxyInfo p); - ProxyProperties getProxy(); + ProxyInfo getProxy(); void setDataDependency(int networkType, boolean met); diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 4dfd3d9..2dcc544 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -16,7 +16,7 @@ package android.net; -import android.net.ProxyProperties; +import android.net.ProxyInfo; import android.os.Parcelable; import android.os.Parcel; import android.text.TextUtils; @@ -65,7 +65,7 @@ public class LinkProperties implements Parcelable { private ArrayList<InetAddress> mDnses = new ArrayList<InetAddress>(); private String mDomains; private ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); - private ProxyProperties mHttpProxy; + private ProxyInfo mHttpProxy; private int mMtu; // Stores the properties of links that are "stacked" above this link. @@ -101,7 +101,7 @@ public class LinkProperties implements Parcelable { mDomains = source.getDomains(); for (RouteInfo r : source.getRoutes()) mRoutes.add(r); mHttpProxy = (source.getHttpProxy() == null) ? - null : new ProxyProperties(source.getHttpProxy()); + null : new ProxyInfo(source.getHttpProxy()); for (LinkProperties l: source.mStackedLinks.values()) { addStackedLink(l); } @@ -295,10 +295,10 @@ public class LinkProperties implements Parcelable { return routes; } - public void setHttpProxy(ProxyProperties proxy) { + public void setHttpProxy(ProxyInfo proxy) { mHttpProxy = proxy; } - public ProxyProperties getHttpProxy() { + public ProxyInfo getHttpProxy() { return mHttpProxy; } @@ -720,7 +720,7 @@ public class LinkProperties implements Parcelable { netProp.addRoute((RouteInfo)in.readParcelable(null)); } if (in.readByte() == 1) { - netProp.setHttpProxy((ProxyProperties)in.readParcelable(null)); + netProp.setHttpProxy((ProxyInfo)in.readParcelable(null)); } ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>(); in.readList(stackedLinks, LinkProperties.class.getClassLoader()); diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java index bea8d1c..daf0065 100644 --- a/core/java/android/net/Proxy.java +++ b/core/java/android/net/Proxy.java @@ -19,6 +19,7 @@ package android.net; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; +import android.net.ProxyInfo; import android.text.TextUtils; import android.util.Log; @@ -63,8 +64,11 @@ public final class Proxy { */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE"; - /** {@hide} **/ - public static final String EXTRA_PROXY_INFO = "proxy"; + /** + * Intent extra included with {@link #PROXY_CHANGE_ACTION} intents. + * It describes the new proxy being used (as a {@link ProxyInfo} object). + */ + public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO"; /** @hide */ public static final int PROXY_VALID = 0; @@ -114,24 +118,14 @@ public final class Proxy { */ public static final java.net.Proxy getProxy(Context ctx, String url) { String host = ""; - if (url != null) { + if ((url != null) && !isLocalHost(host)) { URI uri = URI.create(url); - host = uri.getHost(); - } + ProxySelector proxySelector = ProxySelector.getDefault(); - if (!isLocalHost(host)) { - if (sConnectivityManager == null) { - sConnectivityManager = (ConnectivityManager)ctx.getSystemService( - Context.CONNECTIVITY_SERVICE); - } - if (sConnectivityManager == null) return java.net.Proxy.NO_PROXY; + List<java.net.Proxy> proxyList = proxySelector.select(uri); - ProxyProperties proxyProperties = sConnectivityManager.getProxy(); - - if (proxyProperties != null) { - if (!proxyProperties.isExcluded(host)) { - return proxyProperties.makeProxy(); - } + if (proxyList.size() > 0) { + return proxyList.get(0); } } return java.net.Proxy.NO_PROXY; @@ -275,7 +269,7 @@ public final class Proxy { } /** @hide */ - public static final void setHttpProxySystemProperty(ProxyProperties p) { + public static final void setHttpProxySystemProperty(ProxyInfo p) { String host = null; String port = null; String exclList = null; @@ -283,8 +277,10 @@ public final class Proxy { if (p != null) { host = p.getHost(); port = Integer.toString(p.getPort()); - exclList = p.getExclusionList(); - pacFileUrl = p.getPacFileUrl(); + exclList = p.getExclusionListAsString(); + if (p.getPacFileUrl() != null) { + pacFileUrl = p.getPacFileUrl().toString(); + } } setHttpProxySystemProperty(host, port, exclList, pacFileUrl); } diff --git a/core/java/android/net/ProxyProperties.aidl b/core/java/android/net/ProxyInfo.aidl index 02ea15d..2c91960 100644 --- a/core/java/android/net/ProxyProperties.aidl +++ b/core/java/android/net/ProxyInfo.aidl @@ -17,5 +17,5 @@ package android.net; -parcelable ProxyProperties; +parcelable ProxyInfo; diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyInfo.java index 50f45e8..b40941f 100644 --- a/core/java/android/net/ProxyProperties.java +++ b/core/java/android/net/ProxyInfo.java @@ -21,14 +21,23 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; +import org.apache.http.client.HttpClient; + import java.net.InetSocketAddress; +import java.net.URLConnection; +import java.util.List; import java.util.Locale; /** - * A container class for the http proxy info - * @hide + * Describes a proxy configuration. + * + * Proxy configurations are already integrated within the Apache HTTP stack. + * So {@link URLConnection} and {@link HttpClient} will use them automatically. + * + * Other HTTP stacks will need to obtain the proxy info from + * {@link Proxy#PROXY_CHANGE_ACTION} broadcast as the extra {@link Proxy#EXTRA_PROXY_INFO}. */ -public class ProxyProperties implements Parcelable { +public class ProxyInfo implements Parcelable { private String mHost; private int mPort; @@ -36,32 +45,82 @@ public class ProxyProperties implements Parcelable { private String[] mParsedExclusionList; private String mPacFileUrl; + /** + *@hide + */ public static final String LOCAL_EXCL_LIST = ""; + /** + *@hide + */ public static final int LOCAL_PORT = -1; + /** + *@hide + */ public static final String LOCAL_HOST = "localhost"; - public ProxyProperties(String host, int port, String exclList) { + /** + * Constructs a {@link ProxyInfo} object that points at a Direct proxy + * on the specified host and port. + */ + public static ProxyInfo buildDirectProxy(String host, int port) { + return new ProxyInfo(host, port, null); + } + + /** + * Constructs a {@link ProxyInfo} object that points at a Direct proxy + * on the specified host and port. + * + * The proxy will not be used to access any host in exclusion list, exclList. + * + * @param exclList Hosts to exclude using the proxy on connections for. These + * hosts can use wildcards such as *.example.com. + */ + public static ProxyInfo buildDirectProxy(String host, int port, List<String> exclList) { + String[] array = exclList.toArray(new String[exclList.size()]); + return new ProxyInfo(host, port, TextUtils.join(",", array), array); + } + + /** + * Construct a {@link ProxyInfo} that will download and run the PAC script + * at the specified URL. + */ + public static ProxyInfo buildPacProxy(Uri pacUri) { + return new ProxyInfo(pacUri.toString()); + } + + /** + * Create a ProxyProperties that points at a HTTP Proxy. + * @hide + */ + public ProxyInfo(String host, int port, String exclList) { mHost = host; mPort = port; setExclusionList(exclList); } - public ProxyProperties(String pacFileUrl) { + /** + * Create a ProxyProperties that points at a PAC URL. + * @hide + */ + public ProxyInfo(String pacFileUrl) { mHost = LOCAL_HOST; mPort = LOCAL_PORT; setExclusionList(LOCAL_EXCL_LIST); mPacFileUrl = pacFileUrl; } - // Only used in PacManager after Local Proxy is bound. - public ProxyProperties(String pacFileUrl, int localProxyPort) { + /** + * Only used in PacManager after Local Proxy is bound. + * @hide + */ + public ProxyInfo(String pacFileUrl, int localProxyPort) { mHost = LOCAL_HOST; mPort = localProxyPort; setExclusionList(LOCAL_EXCL_LIST); mPacFileUrl = pacFileUrl; } - private ProxyProperties(String host, int port, String exclList, String[] parsedExclList) { + private ProxyInfo(String host, int port, String exclList, String[] parsedExclList) { mHost = host; mPort = port; mExclusionList = exclList; @@ -70,16 +129,22 @@ public class ProxyProperties implements Parcelable { } // copy constructor instead of clone - public ProxyProperties(ProxyProperties source) { + /** + * @hide + */ + public ProxyInfo(ProxyInfo source) { if (source != null) { mHost = source.getHost(); mPort = source.getPort(); - mPacFileUrl = source.getPacFileUrl(); - mExclusionList = source.getExclusionList(); + mPacFileUrl = source.mPacFileUrl; + mExclusionList = source.getExclusionListAsString(); mParsedExclusionList = source.mParsedExclusionList; } } + /** + * @hide + */ public InetSocketAddress getSocketAddress() { InetSocketAddress inetSocketAddress = null; try { @@ -88,20 +153,46 @@ public class ProxyProperties implements Parcelable { return inetSocketAddress; } - public String getPacFileUrl() { - return mPacFileUrl; + /** + * Returns the URL of the current PAC script or null if there is + * no PAC script. + */ + public Uri getPacFileUrl() { + if (TextUtils.isEmpty(mPacFileUrl)) { + return null; + } + return Uri.parse(mPacFileUrl); } + /** + * When configured to use a Direct Proxy this returns the host + * of the proxy. + */ public String getHost() { return mHost; } + /** + * When configured to use a Direct Proxy this returns the port + * of the proxy + */ public int getPort() { return mPort; } - // comma separated - public String getExclusionList() { + /** + * When configured to use a Direct Proxy this returns the list + * of hosts for which the proxy is ignored. + */ + public String[] getExclusionList() { + return mParsedExclusionList; + } + + /** + * comma separated + * @hide + */ + public String getExclusionListAsString() { return mExclusionList; } @@ -111,33 +202,13 @@ public class ProxyProperties implements Parcelable { if (mExclusionList == null) { mParsedExclusionList = new String[0]; } else { - String splitExclusionList[] = exclusionList.toLowerCase(Locale.ROOT).split(","); - mParsedExclusionList = new String[splitExclusionList.length * 2]; - for (int i = 0; i < splitExclusionList.length; i++) { - String s = splitExclusionList[i].trim(); - if (s.startsWith(".")) s = s.substring(1); - mParsedExclusionList[i*2] = s; - mParsedExclusionList[(i*2)+1] = "." + s; - } + mParsedExclusionList = exclusionList.toLowerCase(Locale.ROOT).split(","); } } - public boolean isExcluded(String url) { - if (TextUtils.isEmpty(url) || mParsedExclusionList == null || - mParsedExclusionList.length == 0) return false; - - Uri u = Uri.parse(url); - String urlDomain = u.getHost(); - if (urlDomain == null) return false; - for (int i = 0; i< mParsedExclusionList.length; i+=2) { - if (urlDomain.equals(mParsedExclusionList[i]) || - urlDomain.endsWith(mParsedExclusionList[i+1])) { - return true; - } - } - return false; - } - + /** + * @hide + */ public boolean isValid() { if (!TextUtils.isEmpty(mPacFileUrl)) return true; return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost, @@ -145,6 +216,9 @@ public class ProxyProperties implements Parcelable { mExclusionList == null ? "" : mExclusionList); } + /** + * @hide + */ public java.net.Proxy makeProxy() { java.net.Proxy proxy = java.net.Proxy.NO_PROXY; if (mHost != null) { @@ -179,17 +253,17 @@ public class ProxyProperties implements Parcelable { @Override public boolean equals(Object o) { - if (!(o instanceof ProxyProperties)) return false; - ProxyProperties p = (ProxyProperties)o; + if (!(o instanceof ProxyInfo)) return false; + ProxyInfo p = (ProxyInfo)o; // If PAC URL is present in either then they must be equal. // Other parameters will only be for fall back. if (!TextUtils.isEmpty(mPacFileUrl)) { return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort; } - if (!TextUtils.isEmpty(p.getPacFileUrl())) { + if (!TextUtils.isEmpty(p.mPacFileUrl)) { return false; } - if (mExclusionList != null && !mExclusionList.equals(p.getExclusionList())) return false; + if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) return false; if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) { return false; } @@ -245,15 +319,15 @@ public class ProxyProperties implements Parcelable { * Implement the Parcelable interface. * @hide */ - public static final Creator<ProxyProperties> CREATOR = - new Creator<ProxyProperties>() { - public ProxyProperties createFromParcel(Parcel in) { + public static final Creator<ProxyInfo> CREATOR = + new Creator<ProxyInfo>() { + public ProxyInfo createFromParcel(Parcel in) { String host = null; int port = 0; if (in.readByte() != 0) { String url = in.readString(); int localPort = in.readInt(); - return new ProxyProperties(url, localPort); + return new ProxyInfo(url, localPort); } if (in.readByte() != 0) { host = in.readString(); @@ -261,13 +335,13 @@ public class ProxyProperties implements Parcelable { } String exclList = in.readString(); String[] parsedExclList = in.readStringArray(); - ProxyProperties proxyProperties = - new ProxyProperties(host, port, exclList, parsedExclList); + ProxyInfo proxyProperties = + new ProxyInfo(host, port, exclList, parsedExclList); return proxyProperties; } - public ProxyProperties[] newArray(int size) { - return new ProxyProperties[size]; + public ProxyInfo[] newArray(int size) { + return new ProxyInfo[size]; } }; } diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/core/java/android/nfc/INfcCardEmulation.aidl index ae9796b..521f4fd 100644 --- a/core/java/android/nfc/INfcCardEmulation.aidl +++ b/core/java/android/nfc/INfcCardEmulation.aidl @@ -34,4 +34,6 @@ interface INfcCardEmulation AidGroup getAidGroupForService(int userHandle, in ComponentName service, String category); boolean removeAidGroupForService(int userHandle, in ComponentName service, String category); List<ApduServiceInfo> getServices(int userHandle, in String category); + boolean setPreferredService(in ComponentName service); + boolean unsetPreferredService(); } diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java index 2820f40..b0449224 100644 --- a/core/java/android/nfc/cardemulation/AidGroup.java +++ b/core/java/android/nfc/cardemulation/AidGroup.java @@ -12,10 +12,15 @@ import android.os.Parcelable; import android.util.Log; /** - * The AidGroup class represents a group of ISO/IEC 7816-4 - * Application Identifiers (AIDs) for a specific application - * category, along with a description resource describing - * the group. + * The AidGroup class represents a group of Application Identifiers (AIDs). + * + * <p>An instance of this object can be used with + * {@link CardEmulation#registerAidGroupForService(android.content.ComponentName, AidGroup)} + * to tell the OS which AIDs are handled by your HCE- or SE-based service. + * + * <p>The format of AIDs is defined in the ISO/IEC 7816-4 specification. This class + * requires the AIDs to be input as a hexadecimal string, with an even amount of + * hexadecimal characters, e.g. "F014811481". */ public final class AidGroup implements Parcelable { /** @@ -33,7 +38,7 @@ public final class AidGroup implements Parcelable { * Creates a new AidGroup object. * * @param aids The list of AIDs present in the group - * @param category The category of this group + * @param category The category of this group, e.g. {@link CardEmulation#CATEGORY_PAYMENT} */ public AidGroup(ArrayList<String> aids, String category) { if (aids == null || aids.size() == 0) { @@ -42,11 +47,12 @@ public final class AidGroup implements Parcelable { if (aids.size() > MAX_NUM_AIDS) { throw new IllegalArgumentException("Too many AIDs in AID group."); } - if (!isValidCategory(category)) { - throw new IllegalArgumentException("Category specified is not valid."); + if (isValidCategory(category)) { + this.category = category; + } else { + this.category = CardEmulation.CATEGORY_OTHER; } this.aids = aids; - this.category = category; this.description = null; } @@ -158,7 +164,7 @@ public final class AidGroup implements Parcelable { } } - boolean isValidCategory(String category) { + static boolean isValidCategory(String category) { return CardEmulation.CATEGORY_PAYMENT.equals(category) || CardEmulation.CATEGORY_OTHER.equals(category); } diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java index 94f35ed..f379ee8 100644 --- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java +++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java @@ -290,6 +290,20 @@ public final class ApduServiceInfo implements Parcelable { return groups; } + /** + * Returns the category to which this service has attributed the AID that is passed in, + * or null if we don't know this AID. + */ + public String getCategoryForAid(String aid) { + ArrayList<AidGroup> groups = getAidGroups(); + for (AidGroup group : groups) { + if (group.aids.contains(aid)) { + return group.category; + } + } + return null; + } + public boolean hasCategory(String category) { return (mStaticAidGroups.containsKey(category) || mDynamicAidGroups.containsKey(category)); } diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java index 41f039c..e24a22a 100644 --- a/core/java/android/nfc/cardemulation/CardEmulation.java +++ b/core/java/android/nfc/cardemulation/CardEmulation.java @@ -18,6 +18,7 @@ package android.nfc.cardemulation; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.app.Activity; import android.app.ActivityThread; import android.content.ComponentName; import android.content.Context; @@ -28,6 +29,7 @@ import android.nfc.NfcAdapter; import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; import android.util.Log; import java.util.HashMap; @@ -248,6 +250,33 @@ public final class CardEmulation { } /** + * Returns whether the user has allowed AIDs registered in the + * specified category to be handled by a service that is preferred + * by the foreground application, instead of by a pre-configured default. + * + * Foreground applications can set such preferences using the + * {@link #setPreferredService(Activity, ComponentName)} method. + * + * @param category The category, e.g. {@link #CATEGORY_PAYMENT} + * @return whether AIDs in the category can be handled by a service + * specified by the foreground app. + */ + public boolean categoryAllowsForegroundPreference(String category) { + if (CATEGORY_PAYMENT.equals(category)) { + boolean preferForeground = false; + try { + preferForeground = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.NFC_PAYMENT_FOREGROUND) != 0; + } catch (SettingNotFoundException e) { + } + return preferForeground; + } else { + // Allowed for all other categories + return true; + } + } + + /** * Returns the service selection mode for the passed in category. * Valid return values are: * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default @@ -269,7 +298,6 @@ public final class CardEmulation { return SELECTION_MODE_ALWAYS_ASK; } } else { - // All other categories are in "only ask if conflict" mode return SELECTION_MODE_ASK_IF_CONFLICT; } } @@ -283,7 +311,7 @@ public final class CardEmulation { * that AID group will be replaced with this one. * * <p>Note that you can only register AIDs for a service that - * is running under the same UID as you are. Typically + * is running under the same UID as the caller of this API. Typically * this means you need to call this from the same * package as the service itself, though UIDs can also * be shared between packages using shared UIDs. @@ -352,7 +380,7 @@ public final class CardEmulation { * method. It will *not* remove AID groups that were statically registered in * the manifest. If a dynamically registered AID group is removed using * this method, and a statically registered AID group for the same category - * exists in the manifest, that AID group will become active again. + * exists in the manifest, the static AID group will become active again. * * @param service The component name of the service * @param category The category of the AID group to be removed, e.g. {@link #CATEGORY_PAYMENT} @@ -378,6 +406,96 @@ public final class CardEmulation { } /** + * Allows a foreground application to specify which card emulation service + * should be preferred while a specific Activity is in the foreground. + * + * <p>The specified Activity must currently be in resumed state. A good + * paradigm is to call this method in your {@link Activity#onResume}, and to call + * {@link #unsetPreferredService(Activity)} in your {@link Activity#onPause}. + * + * <p>This method call will fail in two specific scenarios: + * <ul> + * <li> If the service registers one or more AIDs in the {@link #CATEGORY_PAYMENT} + * category, but the user has indicated that foreground apps are not allowed + * to override the default payment service. + * <li> If the service registers one or more AIDs in the {@link #CATEGORY_OTHER} + * category that are also handled by the default payment service, and the + * user has indicated that foreground apps are not allowed to override the + * default payment service. + * </ul> + * + * <p> Use {@link #categoryAllowsForegroundPreference(String)} to determine + * whether foreground apps can override the default payment service. + * + * <p>Note that this preference is not persisted by the OS, and hence must be + * called every time the Activity is resumed. + * + * @param activity The activity which prefers this service to be invoked + * @param service The service to be preferred while this activity is in the foreground + * @return whether the registration was successful + */ + public boolean setPreferredService(Activity activity, ComponentName service) { + // Verify the activity is in the foreground before calling into NfcService + if (activity == null || service == null) { + throw new NullPointerException("activity or service or category is null"); + } + if (!activity.isResumed()) { + throw new IllegalArgumentException("Activity must be resumed."); + } + try { + return sService.setPreferredService(service); + } catch (RemoteException e) { + // Try one more time + recoverService(); + if (sService == null) { + Log.e(TAG, "Failed to recover CardEmulationService."); + return false; + } + try { + return sService.setPreferredService(service); + } catch (RemoteException ee) { + Log.e(TAG, "Failed to reach CardEmulationService."); + return false; + } + } + } + + /** + * Unsets the preferred service for the specified Activity. + * + * <p>Note that the specified Activity must still be in resumed + * state at the time of this call. A good place to call this method + * is in your {@link Activity#onPause} implementation. + * + * @param activity The activity which the service was registered for + * @return true when successful + */ + public boolean unsetPreferredService(Activity activity) { + if (activity == null) { + throw new NullPointerException("activity is null"); + } + if (!activity.isResumed()) { + throw new IllegalArgumentException("Activity must be resumed."); + } + try { + return sService.unsetPreferredService(); + } catch (RemoteException e) { + // Try one more time + recoverService(); + if (sService == null) { + Log.e(TAG, "Failed to recover CardEmulationService."); + return false; + } + try { + return sService.unsetPreferredService(); + } catch (RemoteException ee) { + Log.e(TAG, "Failed to reach CardEmulationService."); + return false; + } + } + } + + /** * @hide */ public boolean setDefaultServiceForCategory(ComponentName service, String category) { diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index e78ce33..8b7467f 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -135,7 +135,7 @@ public abstract class BatteryStats implements Parcelable { /** * Bump the version on this if the checkin format changes. */ - private static final int BATTERY_STATS_CHECKIN_VERSION = 7; + private static final int BATTERY_STATS_CHECKIN_VERSION = 8; private static final long BYTES_PER_KB = 1024; private static final long BYTES_PER_MB = 1048576; // 1024^2 diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 899a958..cd47099 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -36,6 +36,7 @@ interface IUserManager { Bitmap getUserIcon(int userHandle); List<UserInfo> getUsers(boolean excludeDying); List<UserInfo> getProfiles(int userHandle, boolean enabledOnly); + UserInfo getProfileParent(int userHandle); UserInfo getUserInfo(int userHandle); boolean isRestricted(); void setGuestEnabled(boolean enable); diff --git a/core/java/com/android/internal/os/PkgUsageStats.aidl b/core/java/android/os/ParcelableParcel.aidl index 8305271..61f730c 100644 --- a/core/java/com/android/internal/os/PkgUsageStats.aidl +++ b/core/java/android/os/ParcelableParcel.aidl @@ -1,20 +1,19 @@ -/* //device/java/android/android/content/Intent.aidl +/* +** Copyright 2014, The Android Open Source Project ** -** Copyright 2007, 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 ** -** 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 ** -** 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 +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and ** limitations under the License. */ -package com.android.internal.os; +package android.os; -parcelable PkgUsageStats; +parcelable ParcelableParcel; diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 84639eb..312cdbe 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -234,6 +234,38 @@ public class UserManager { */ public static final String DISALLOW_CONFIG_APPS = "no_config_apps"; + /** + * Key for user restrictions. Specifies if a user is disallowed from mounting + * physical external media. The default value is <code>false</code>. + * <p/> + * Type: Boolean + * @see #setUserRestrictions(Bundle) + * @see #getUserRestrictions() + */ + public static final String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media"; + + /** + * Key for user restrictions. Specifies if a user is disallowed from adjusting microphone + * volume. + * The default value is <code>false</code>. + * <p/> + * Type: Boolean + * @see #setUserRestrictions(Bundle) + * @see #getUserRestrictions() + */ + public static final String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone"; + + /** + * Key for user restrictions. Specifies if a user is disallowed from adjusting the master + * volume. + * The default value is <code>false</code>. + * <p/> + * Type: Boolean + * @see #setUserRestrictions(Bundle) + * @see #getUserRestrictions() + */ + public static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume"; + /** @hide */ public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3; /** @hide */ @@ -269,7 +301,8 @@ public class UserManager { } /** - * Returns the user handle for the user that this application is running for. + * Returns the user handle for the user that the calling process is running on. + * * @return the user handle of the user making this call. * @hide */ @@ -585,7 +618,8 @@ public class UserManager { } /** - * Returns a list of UserHandles for profiles associated with this user, including this user. + * Returns a list of UserHandles for profiles associated with the user that the calling process + * is running on, including the user itself. * * @return A non-empty list of UserHandles associated with the calling user. */ @@ -606,6 +640,21 @@ public class UserManager { } /** + * Returns the parent of the profile which this method is called from + * or null if called from a user that is not a profile. + * + * @hide + */ + public UserInfo getProfileParent(int userHandle) { + try { + return mService.getProfileParent(userHandle); + } catch (RemoteException re) { + Log.w(TAG, "Could not get profile parent", re); + return null; + } + } + + /** * If the target user is a managed profile of the calling user or the caller * is itself a managed profile, then this returns a badged copy of the given * icon to be able to distinguish it from the original icon. @@ -632,7 +681,7 @@ public class UserManager { private int getBadgeResIdForUser(int userHandle) { // Return the framework-provided badge. - List<UserInfo> userProfiles = getProfiles(UserHandle.myUserId()); + List<UserInfo> userProfiles = getProfiles(getUserHandle()); for (UserInfo user : userProfiles) { if (user.id == userHandle && user.isManagedProfile()) { @@ -661,7 +710,7 @@ public class UserManager { /** * Returns information for all users on this device. Requires * {@link android.Manifest.permission#MANAGE_USERS} permission. - * + * * @param excludeDying specify if the list should exclude users being * removed. * @return the list of users that were created. diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java index e4f73cb..811751d 100644 --- a/core/java/android/print/PrintManager.java +++ b/core/java/android/print/PrintManager.java @@ -167,7 +167,7 @@ public final class PrintManager { /** * Callback notifying that a print job state changed. - * + * * @param printJobId The print job id. */ public void onPrintJobStateChanged(PrintJobId printJobId); @@ -175,7 +175,7 @@ public final class PrintManager { /** * Creates a new instance. - * + * * @param context The current context in which to operate. * @param service The backing system service. * @hide @@ -207,13 +207,17 @@ public final class PrintManager { /** * Creates an instance that can access all print jobs. - * + * * @param userId The user id for which to get all print jobs. * @return An instance if the caller has the permission to access all print * jobs, null otherwise. * @hide */ public PrintManager getGlobalPrintManagerForUser(int userId) { + if (mService == null) { + Log.w(LOG_TAG, "Feature android.software.print not available"); + return null; + } return new PrintManager(mContext, mService, userId, APP_ID_ANY); } @@ -228,11 +232,15 @@ public final class PrintManager { /** * Adds a listener for observing the state of print jobs. - * + * * @param listener The listener to add. * @hide */ public void addPrintJobStateChangeListener(PrintJobStateChangeListener listener) { + if (mService == null) { + Log.w(LOG_TAG, "Feature android.software.print not available"); + return; + } if (mPrintJobStateChangeListeners == null) { mPrintJobStateChangeListeners = new ArrayMap<PrintJobStateChangeListener, PrintJobStateChangeListenerWrapper>(); @@ -249,11 +257,15 @@ public final class PrintManager { /** * Removes a listener for observing the state of print jobs. - * + * * @param listener The listener to remove. * @hide */ public void removePrintJobStateChangeListener(PrintJobStateChangeListener listener) { + if (mService == null) { + Log.w(LOG_TAG, "Feature android.software.print not available"); + return; + } if (mPrintJobStateChangeListeners == null) { return; } @@ -275,12 +287,16 @@ public final class PrintManager { /** * Gets a print job given its id. - * + * * @return The print job list. * @see PrintJob * @hide */ public PrintJob getPrintJob(PrintJobId printJobId) { + if (mService == null) { + Log.w(LOG_TAG, "Feature android.software.print not available"); + return null; + } try { PrintJobInfo printJob = mService.getPrintJobInfo(printJobId, mAppId, mUserId); if (printJob != null) { @@ -294,11 +310,15 @@ public final class PrintManager { /** * Gets the print jobs for this application. - * + * * @return The print job list. * @see PrintJob */ public List<PrintJob> getPrintJobs() { + if (mService == null) { + Log.w(LOG_TAG, "Feature android.software.print not available"); + return Collections.emptyList(); + } try { List<PrintJobInfo> printJobInfos = mService.getPrintJobInfos(mAppId, mUserId); if (printJobInfos == null) { @@ -317,6 +337,10 @@ public final class PrintManager { } void cancelPrintJob(PrintJobId printJobId) { + if (mService == null) { + Log.w(LOG_TAG, "Feature android.software.print not available"); + return; + } try { mService.cancelPrintJob(printJobId, mAppId, mUserId); } catch (RemoteException re) { @@ -325,6 +349,10 @@ public final class PrintManager { } void restartPrintJob(PrintJobId printJobId) { + if (mService == null) { + Log.w(LOG_TAG, "Feature android.software.print not available"); + return; + } try { mService.restartPrintJob(printJobId, mAppId, mUserId); } catch (RemoteException re) { @@ -383,6 +411,10 @@ public final class PrintManager { */ public PrintJob print(String printJobName, PrintDocumentAdapter documentAdapter, PrintAttributes attributes) { + if (mService == null) { + Log.w(LOG_TAG, "Feature android.software.print not available"); + return null; + } if (!(mContext instanceof Activity)) { throw new IllegalStateException("Can print only from an activity"); } @@ -418,11 +450,15 @@ public final class PrintManager { /** * Gets the list of enabled print services. - * + * * @return The enabled service list or an empty list. * @hide */ public List<PrintServiceInfo> getEnabledPrintServices() { + if (mService == null) { + Log.w(LOG_TAG, "Feature android.software.print not available"); + return Collections.emptyList(); + } try { List<PrintServiceInfo> enabledServices = mService.getEnabledPrintServices(mUserId); if (enabledServices != null) { @@ -436,11 +472,15 @@ public final class PrintManager { /** * Gets the list of installed print services. - * + * * @return The installed service list or an empty list. * @hide */ public List<PrintServiceInfo> getInstalledPrintServices() { + if (mService == null) { + Log.w(LOG_TAG, "Feature android.software.print not available"); + return Collections.emptyList(); + } try { List<PrintServiceInfo> installedServices = mService.getInstalledPrintServices(mUserId); if (installedServices != null) { @@ -456,6 +496,10 @@ public final class PrintManager { * @hide */ public PrinterDiscoverySession createPrinterDiscoverySession() { + if (mService == null) { + Log.w(LOG_TAG, "Feature android.software.print not available"); + return null; + } return new PrinterDiscoverySession(mService, mContext, mUserId); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index d5a3bcb..1847b55 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -2823,7 +2823,6 @@ public final class Settings { MOVED_TO_GLOBAL.add(Settings.Global.TETHER_SUPPORTED); MOVED_TO_GLOBAL.add(Settings.Global.USB_MASS_STORAGE_ENABLED); MOVED_TO_GLOBAL.add(Settings.Global.USE_GOOGLE_MAIL); - MOVED_TO_GLOBAL.add(Settings.Global.WEB_AUTOFILL_QUERY_URL); MOVED_TO_GLOBAL.add(Settings.Global.WIFI_COUNTRY_CODE); MOVED_TO_GLOBAL.add(Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS); MOVED_TO_GLOBAL.add(Settings.Global.WIFI_FREQUENCY_BAND); @@ -2838,6 +2837,8 @@ public final class Settings { MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SAVED_STATE); MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS); MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_ENHANCED_AUTO_JOIN); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NETWORK_SHOW_RSSI); MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_ON); MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED); MOVED_TO_GLOBAL.add(Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON); @@ -4528,6 +4529,12 @@ public final class Settings { public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component"; /** + * Whether NFC payment is handled by the foreground application or a default. + * @hide + */ + public static final String NFC_PAYMENT_FOREGROUND = "nfc_payment_foreground"; + + /** * Specifies the package name currently configured to be the primary sms application * @hide */ @@ -5353,11 +5360,6 @@ public final class Settings { */ public static final String USE_GOOGLE_MAIL = "use_google_mail"; - /** Autofill server address (Used in WebView/browser). - * {@hide} */ - public static final String WEB_AUTOFILL_QUERY_URL = - "web_autofill_query_url"; - /** * Whether Wifi display is enabled/disabled * 0=disabled. 1=enabled. @@ -5469,7 +5471,21 @@ public final class Settings { public static final String WIFI_SUPPLICANT_SCAN_INTERVAL_MS = "wifi_supplicant_scan_interval_ms"; - /** + /** + * whether frameworks handles wifi auto-join + * @hide + */ + public static final String WIFI_ENHANCED_AUTO_JOIN = + "wifi_enhanced_auto_join"; + + /** + * whether settings show RSSI + * @hide + */ + public static final String WIFI_NETWORK_SHOW_RSSI = + "wifi_network_show_rssi"; + + /** * The interval in milliseconds to scan at supplicant when p2p is connected * @hide */ diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java index 2549fde..49a0138 100644 --- a/core/java/android/transition/Transition.java +++ b/core/java/android/transition/Transition.java @@ -351,18 +351,8 @@ public abstract class Transition implements Cloneable { } ArrayMap<View, TransitionValues> endCopy = new ArrayMap<View, TransitionValues>(endValues.viewValues); - SparseArray<TransitionValues> endIdCopy = - new SparseArray<TransitionValues>(endValues.idValues.size()); - for (int i = 0; i < endValues.idValues.size(); ++i) { - int id = endValues.idValues.keyAt(i); - endIdCopy.put(id, endValues.idValues.valueAt(i)); - } - LongSparseArray<TransitionValues> endItemIdCopy = - new LongSparseArray<TransitionValues>(endValues.itemIdValues.size()); - for (int i = 0; i < endValues.itemIdValues.size(); ++i) { - long id = endValues.itemIdValues.keyAt(i); - endItemIdCopy.put(id, endValues.itemIdValues.valueAt(i)); - } + SparseArray<TransitionValues> endIdCopy = endValues.idValues.clone(); + LongSparseArray<TransitionValues> endItemIdCopy = endValues.itemIdValues.clone(); // Walk through the start values, playing everything we find // Remove from the end set as we go ArrayList<TransitionValues> startValuesList = new ArrayList<TransitionValues>(); @@ -376,21 +366,17 @@ public abstract class Transition implements Cloneable { } if (!isInListView) { int id = view.getId(); - start = startValues.viewValues.get(view) != null ? - startValues.viewValues.get(view) : startValues.idValues.get(id); - if (endValues.viewValues.get(view) != null) { - end = endValues.viewValues.get(view); + start = startValues.viewValues.get(view); + end = endValues.viewValues.get(view); + if (end != null) { endCopy.remove(view); } else if (id != View.NO_ID) { - end = endValues.idValues.get(id); - View removeView = null; - for (View viewToRemove : endCopy.keySet()) { - if (viewToRemove.getId() == id) { - removeView = viewToRemove; - } - } - if (removeView != null) { - endCopy.remove(removeView); + end = endIdCopy.get(id); + if (end == null || startValues.viewValues.containsKey(end.view)) { + end = null; + id = View.NO_ID; + } else { + endCopy.remove(end.view); } } endIdCopy.remove(id); @@ -423,36 +409,16 @@ public abstract class Transition implements Cloneable { } } // Now walk through the remains of the end set + // We've already matched everything from start to end, everything else doesn't match. for (View view : endCopy.keySet()) { int id = view.getId(); if (isValidTarget(view, id)) { - TransitionValues start = startValues.viewValues.get(view) != null ? - startValues.viewValues.get(view) : startValues.idValues.get(id); + TransitionValues start = null; TransitionValues end = endCopy.get(view); - endIdCopy.remove(id); startValuesList.add(start); endValuesList.add(end); } } - int endIdCopySize = endIdCopy.size(); - for (int i = 0; i < endIdCopySize; ++i) { - int id = endIdCopy.keyAt(i); - if (isValidTarget(null, id)) { - TransitionValues start = startValues.idValues.get(id); - TransitionValues end = endIdCopy.get(id); - startValuesList.add(start); - endValuesList.add(end); - } - } - int endItemIdCopySize = endItemIdCopy.size(); - for (int i = 0; i < endItemIdCopySize; ++i) { - long id = endItemIdCopy.keyAt(i); - // TODO: Deal with targetIDs and itemIDs - TransitionValues start = startValues.itemIdValues.get(id); - TransitionValues end = endItemIdCopy.get(id); - startValuesList.add(start); - endValuesList.add(end); - } ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators(); long minStartDelay = Long.MAX_VALUE; int minAnimator = mAnimators.size(); diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 11948b2..6c451eb 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -43,7 +43,6 @@ import android.text.TextUtils; class GLES20Canvas extends HardwareCanvas { // Must match modifiers used in the JNI layer private static final int MODIFIER_NONE = 0; - private static final int MODIFIER_SHADOW = 1; private static final int MODIFIER_SHADER = 2; private final boolean mOpaque; @@ -264,27 +263,6 @@ class GLES20Canvas extends HardwareCanvas { private static native int nCallDrawGLFunction(long renderer, long drawGLFunction); - @Override - public int invokeFunctors(Rect dirty) { - return nInvokeFunctors(mRenderer, dirty); - } - - private static native int nInvokeFunctors(long renderer, Rect dirty); - - @Override - public void detachFunctor(long functor) { - nDetachFunctor(mRenderer, functor); - } - - private static native void nDetachFunctor(long renderer, long functor); - - @Override - public void attachFunctor(long functor) { - nAttachFunctor(mRenderer, functor); - } - - private static native void nAttachFunctor(long renderer, long functor); - /////////////////////////////////////////////////////////////////////////// // Memory /////////////////////////////////////////////////////////////////////////// @@ -1318,12 +1296,6 @@ class GLES20Canvas extends HardwareCanvas { private int setupModifiers(Paint paint) { int modifiers = MODIFIER_NONE; - if (paint.hasShadow) { - nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy, - paint.shadowColor); - modifiers |= MODIFIER_SHADOW; - } - final Shader shader = paint.getShader(); if (shader != null) { nSetupShader(mRenderer, shader.native_shader); @@ -1336,12 +1308,6 @@ class GLES20Canvas extends HardwareCanvas { private int setupModifiers(Paint paint, int flags) { int modifiers = MODIFIER_NONE; - if (paint.hasShadow && (flags & MODIFIER_SHADOW) != 0) { - nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy, - paint.shadowColor); - modifiers |= MODIFIER_SHADOW; - } - final Shader shader = paint.getShader(); if (shader != null && (flags & MODIFIER_SHADER) != 0) { nSetupShader(mRenderer, shader.native_shader); @@ -1352,8 +1318,6 @@ class GLES20Canvas extends HardwareCanvas { } private static native void nSetupShader(long renderer, long shader); - private static native void nSetupShadow(long renderer, float radius, - float dx, float dy, int color); private static native void nResetModifiers(long renderer, int modifiers); } diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java index 97339cc..7b49006 100644 --- a/core/java/android/view/GLRenderer.java +++ b/core/java/android/view/GLRenderer.java @@ -168,7 +168,6 @@ public class GLRenderer extends HardwareRenderer { private final Rect mRedrawClip = new Rect(); private final int[] mSurfaceSize = new int[2]; - private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable(); private long mDrawDelta = Long.MAX_VALUE; @@ -654,6 +653,11 @@ public class GLRenderer extends HardwareRenderer { } @Override + void setOpaque(boolean opaque) { + // Not supported + } + + @Override boolean loadSystemProperties() { boolean value; boolean changed = false; @@ -1116,22 +1120,6 @@ public class GLRenderer extends HardwareRenderer { mName = name; } - class FunctorsRunnable implements Runnable { - View.AttachInfo attachInfo; - - @Override - public void run() { - final HardwareRenderer renderer = attachInfo.mHardwareRenderer; - if (renderer == null || !renderer.isEnabled() || renderer != GLRenderer.this) { - return; - } - - if (checkRenderContext() != SURFACE_STATE_ERROR) { - mCanvas.invokeFunctors(mRedrawClip); - } - } - } - @Override void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) { @@ -1366,23 +1354,6 @@ public class GLRenderer extends HardwareRenderer { } } - @Override - void detachFunctor(long functor) { - if (mCanvas != null) { - mCanvas.detachFunctor(functor); - } - } - - @Override - void attachFunctor(View.AttachInfo attachInfo, long functor) { - if (mCanvas != null) { - mCanvas.attachFunctor(functor); - mFunctorsRunnable.attachInfo = attachInfo; - attachInfo.mHandler.removeCallbacks(mFunctorsRunnable); - attachInfo.mHandler.postDelayed(mFunctorsRunnable, 0); - } - } - /** * Ensures the current EGL context and surface are the ones we expect. * This method throws an IllegalStateException if invoked from a thread diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java index 7ec2cc6..9568760 100644 --- a/core/java/android/view/HardwareCanvas.java +++ b/core/java/android/view/HardwareCanvas.java @@ -111,45 +111,6 @@ public abstract class HardwareCanvas extends Canvas { } /** - * Invoke all the functors who requested to be invoked during the previous frame. - * - * @param dirty Ignored - * - * @return Ignored - * - * @hide - */ - public int invokeFunctors(Rect dirty) { - return RenderNode.STATUS_DONE; - } - - /** - * Detaches the specified functor from the current functor execution queue. - * - * @param functor The native functor to remove from the execution queue. - * - * @see #invokeFunctors(android.graphics.Rect) - * @see #callDrawGLFunction(long) - * @see #detachFunctor(long) - * - * @hide - */ - abstract void detachFunctor(long functor); - - /** - * Attaches the specified functor to the current functor execution queue. - * - * @param functor The native functor to add to the execution queue. - * - * @see #invokeFunctors(android.graphics.Rect) - * @see #callDrawGLFunction(long) - * @see #detachFunctor(long) - * - * @hide - */ - abstract void attachFunctor(long functor); - - /** * Indicates that the specified layer must be updated as soon as possible. * * @param layer The layer to update diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index d31c79d..e366697 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -423,28 +423,6 @@ public abstract class HardwareRenderer { abstract boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap); /** - * Detaches the specified functor from the current functor execution queue. - * - * @param functor The native functor to remove from the execution queue. - * - * @see HardwareCanvas#callDrawGLFunction(int) - * @see #attachFunctor(android.view.View.AttachInfo, long) - */ - abstract void detachFunctor(long functor); - - /** - * Schedules the specified functor in the functors execution queue. - * - * @param attachInfo AttachInfo tied to this renderer. - * @param functor The native functor to insert in the execution queue. - * - * @see HardwareCanvas#callDrawGLFunction(int) - * @see #detachFunctor(long) - * - */ - abstract void attachFunctor(View.AttachInfo attachInfo, long functor); - - /** * Schedules the functor for execution in either kModeProcess or * kModeProcessNoContext, depending on whether or not there is an EGLContext. * @@ -491,6 +469,11 @@ public abstract class HardwareRenderer { abstract void setName(String name); /** + * Change the HardwareRenderer's opacity + */ + abstract void setOpaque(boolean opaque); + + /** * Creates a hardware renderer using OpenGL. * * @param translucent True if the surface is translucent, false otherwise diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 05e202b..2d1016a 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -1685,10 +1685,6 @@ public class KeyEvent extends InputEvent implements Parcelable { case KeyEvent.KEYCODE_BRIGHTNESS_DOWN: case KeyEvent.KEYCODE_BRIGHTNESS_UP: case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: - case KeyEvent.KEYCODE_DPAD_UP: - case KeyEvent.KEYCODE_DPAD_RIGHT: - case KeyEvent.KEYCODE_DPAD_DOWN: - case KeyEvent.KEYCODE_DPAD_LEFT: return true; } diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 0bf99d3..2587ba1 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -148,6 +148,11 @@ public class ThreadedRenderer extends HardwareRenderer { } @Override + void setOpaque(boolean opaque) { + nSetOpaque(mNativeProxy, opaque); + } + + @Override int getWidth() { return mWidth; } @@ -215,16 +220,6 @@ public class ThreadedRenderer extends HardwareRenderer { } @Override - void detachFunctor(long functor) { - // no-op, we never attach functors to need to detach them - } - - @Override - void attachFunctor(AttachInfo attachInfo, long functor) { - invokeFunctor(functor, true); - } - - @Override void invokeFunctor(long functor, boolean waitForCompletion) { nInvokeFunctor(mNativeProxy, functor, waitForCompletion); } @@ -312,6 +307,7 @@ public class ThreadedRenderer extends HardwareRenderer { private static native void nUpdateSurface(long nativeProxy, Surface window); private static native void nPauseSurface(long nativeProxy, Surface window); private static native void nSetup(long nativeProxy, int width, int height); + private static native void nSetOpaque(long nativeProxy, boolean opaque); private static native void nSetDisplayListData(long nativeProxy, long displayList, long newData); private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos, diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index d8fcfc5..bef96b1 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -16,7 +16,9 @@ package android.view; +import android.animation.AnimatorInflater; import android.animation.RevealAnimator; +import android.animation.StateListAnimator; import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; @@ -667,6 +669,7 @@ import java.util.concurrent.atomic.AtomicInteger; * @attr ref android.R.styleable#View_scrollbarTrackVertical * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack + * @attr ref android.R.styleable#View_stateListAnimator * @attr ref android.R.styleable#View_sharedElementName * @attr ref android.R.styleable#View_soundEffectsEnabled * @attr ref android.R.styleable#View_tag @@ -3258,6 +3261,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private Outline mOutline; /** + * Animator that automatically runs based on state changes. + */ + private StateListAnimator mStateListAnimator; + + /** * When this view has focus and the next focus is {@link #FOCUS_LEFT}, * the user may specify which view to go to next. */ @@ -3995,6 +4003,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, case R.styleable.View_nestedScrollingEnabled: setNestedScrollingEnabled(a.getBoolean(attr, false)); break; + case R.styleable.View_stateListAnimator: + setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, + a.getResourceId(attr, 0))); + break; } } @@ -10620,6 +10632,40 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Returns the current StateListAnimator if exists. + * + * @return StateListAnimator or null if it does not exists + * @see #setStateListAnimator(android.animation.StateListAnimator) + */ + public StateListAnimator getStateListAnimator() { + return mStateListAnimator; + } + + /** + * Attaches the provided StateListAnimator to this View. + * <p> + * Any previously attached StateListAnimator will be detached. + * + * @param stateListAnimator The StateListAnimator to update the view + * @see {@link android.animation.StateListAnimator} + */ + public void setStateListAnimator(StateListAnimator stateListAnimator) { + if (mStateListAnimator == stateListAnimator) { + return; + } + if (mStateListAnimator != null) { + mStateListAnimator.setTarget(null); + } + mStateListAnimator = stateListAnimator; + if (stateListAnimator != null) { + stateListAnimator.setTarget(this); + if (isAttachedToWindow()) { + stateListAnimator.setState(getDrawableState()); + } + } + } + + /** * Sets the outline of the view, which defines the shape of the shadow it * casts. * <p> @@ -12835,7 +12881,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, destroyLayer(false); cleanupDraw(); - mCurrentAnimation = null; } @@ -15489,9 +15534,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * This function is called whenever the state of the view changes in such * a way that it impacts the state of drawables being shown. - * - * <p>Be sure to call through to the superclass when overriding this - * function. + * <p> + * If the View has a StateListAnimator, it will also be called to run necessary state + * change animations. + * <p> + * Be sure to call through to the superclass when overriding this function. * * @see Drawable#setState(int[]) */ @@ -15500,6 +15547,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (d != null && d.isStateful()) { d.setState(getDrawableState()); } + + if (mStateListAnimator != null) { + mStateListAnimator.setState(getDrawableState()); + } } /** @@ -15644,11 +15695,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} * on all Drawable objects associated with this view. + * <p> + * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator + * attached to this view. */ public void jumpDrawablesToCurrentState() { if (mBackground != null) { mBackground.jumpToCurrentState(); } + if (mStateListAnimator != null) { + mStateListAnimator.jumpToCurrentState(); + } } /** diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index db87394..9b09d85 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -665,18 +665,9 @@ public final class ViewRootImpl implements ViewParent, mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG_FLUSH_LAYER_UPDATES)); } - public void attachFunctor(long functor) { - //noinspection SimplifiableIfStatement - if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { - mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor); - } - } - public void detachFunctor(long functor) { + // TODO: Make the resize buffer some other way to not need this block mBlockResizeBuffer = true; - if (mAttachInfo.mHardwareRenderer != null) { - mAttachInfo.mHardwareRenderer.detachFunctor(functor); - } } public boolean invokeFunctor(long functor, boolean waitForCompletion) { @@ -719,12 +710,15 @@ public final class ViewRootImpl implements ViewParent, if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled && forceHwAccelerated)) { - // Don't enable hardware acceleration when we're not on the main thread - if (!HardwareRenderer.sSystemRendererDisabled && - Looper.getMainLooper() != Looper.myLooper()) { - Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware " - + "acceleration outside of the main thread, aborting"); - return; + if (!HardwareRenderer.sUseRenderThread) { + // TODO: Delete + // Don't enable hardware acceleration when we're not on the main thread + if (!HardwareRenderer.sSystemRendererDisabled && + Looper.getMainLooper() != Looper.myLooper()) { + Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware " + + "acceleration outside of the main thread, aborting"); + return; + } } if (mAttachInfo.mHardwareRenderer != null) { @@ -6174,8 +6168,10 @@ public final class ViewRootImpl implements ViewParent, } void changeCanvasOpacity(boolean opaque) { - // TODO(romainguy): recreate Canvas (software or hardware) to reflect the opacity change. Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque); + if (mAttachInfo.mHardwareRenderer != null) { + mAttachInfo.mHardwareRenderer.setOpaque(opaque); + } } class TakenSurfaceHolder extends BaseSurfaceHolder { diff --git a/core/java/android/view/inputmethod/CorrectionInfo.java b/core/java/android/view/inputmethod/CorrectionInfo.java index 1b04e49..a43dfe8 100644 --- a/core/java/android/view/inputmethod/CorrectionInfo.java +++ b/core/java/android/view/inputmethod/CorrectionInfo.java @@ -88,16 +88,15 @@ public final class CorrectionInfo implements Parcelable { /** * Used to make this class parcelable. */ - public static final Parcelable.Creator<CorrectionInfo> CREATOR - = new Parcelable.Creator<CorrectionInfo>() { - public CorrectionInfo createFromParcel(Parcel source) { - return new CorrectionInfo(source); - } - - public CorrectionInfo[] newArray(int size) { - return new CorrectionInfo[size]; - } - }; + public static final Parcelable.Creator<CorrectionInfo> CREATOR = + new Parcelable.Creator<CorrectionInfo>() { + public CorrectionInfo createFromParcel(Parcel source) { + return new CorrectionInfo(source); + } + public CorrectionInfo[] newArray(int size) { + return new CorrectionInfo[size]; + } + }; public int describeContents() { return 0; diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.aidl b/core/java/android/view/inputmethod/CursorAnchorInfo.aidl new file mode 100644 index 0000000..2ee9edb --- /dev/null +++ b/core/java/android/view/inputmethod/CursorAnchorInfo.aidl @@ -0,0 +1,19 @@ +/* + * 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. + */ + +package android.view.inputmethod; + +parcelable CursorAnchorInfo; diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java new file mode 100644 index 0000000..92455df --- /dev/null +++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java @@ -0,0 +1,449 @@ +/* + * 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. + */ + +package android.view.inputmethod; + +import android.graphics.Matrix; +import android.graphics.RectF; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.Layout; +import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder; + +import java.util.Objects; + +/** + * Positional information about the text insertion point and characters in the composition string. + * + * <p>This class encapsulates locations of the text insertion point and the composition string in + * the screen coordinates so that IMEs can render their UI components near where the text is + * actually inserted.</p> + */ +public final class CursorAnchorInfo implements Parcelable { + private final int mSelectionStart; + private final int mSelectionEnd; + private final int mCandidatesStart; + private final int mCandidatesEnd; + + /** + * Horizontal position of the insertion marker, in the local coordinates that will be + * transformed with the transformation matrix when rendered on the screen. This should be + * calculated or compatible with {@link Layout#getPrimaryHorizontal(int)}. This can be + * {@code java.lang.Float.NaN} when no value is specified. + */ + private final float mInsertionMarkerHorizontal; + /** + * Vertical position of the insertion marker, in the local coordinates that will be + * transformed with the transformation matrix when rendered on the screen. This should be + * calculated or compatible with {@link Layout#getLineTop(int)}. This can be + * {@code java.lang.Float.NaN} when no value is specified. + */ + private final float mInsertionMarkerTop; + /** + * Vertical position of the insertion marker, in the local coordinates that will be + * transformed with the transformation matrix when rendered on the screen. This should be + * calculated or compatible with {@link Layout#getLineBaseline(int)}. This can be + * {@code java.lang.Float.NaN} when no value is specified. + */ + private final float mInsertionMarkerBaseline; + /** + * Vertical position of the insertion marker, in the local coordinates that will be + * transformed with the transformation matrix when rendered on the screen. This should be + * calculated or compatible with {@link Layout#getLineBottom(int)}. This can be + * {@code java.lang.Float.NaN} when no value is specified. + */ + private final float mInsertionMarkerBottom; + + /** + * Container of rectangular position of characters, keyed with character index in a unit of + * Java chars, in the local coordinates that will be transformed with the transformation matrix + * when rendered on the screen. + */ + private final SparseRectFArray mCharacterRects; + + /** + * Transformation matrix that is applied to any positional information of this class to + * transform local coordinates into screen coordinates. + */ + private final Matrix mMatrix; + + public CursorAnchorInfo(final Parcel source) { + mSelectionStart = source.readInt(); + mSelectionEnd = source.readInt(); + mCandidatesStart = source.readInt(); + mCandidatesEnd = source.readInt(); + mInsertionMarkerHorizontal = source.readFloat(); + mInsertionMarkerTop = source.readFloat(); + mInsertionMarkerBaseline = source.readFloat(); + mInsertionMarkerBottom = source.readFloat(); + mCharacterRects = source.readParcelable(SparseRectFArray.class.getClassLoader()); + mMatrix = new Matrix(); + mMatrix.setValues(source.createFloatArray()); + } + + /** + * Used to package this object into a {@link Parcel}. + * + * @param dest The {@link Parcel} to be written. + * @param flags The flags used for parceling. + */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mSelectionStart); + dest.writeInt(mSelectionEnd); + dest.writeInt(mCandidatesStart); + dest.writeInt(mCandidatesEnd); + dest.writeFloat(mInsertionMarkerHorizontal); + dest.writeFloat(mInsertionMarkerTop); + dest.writeFloat(mInsertionMarkerBaseline); + dest.writeFloat(mInsertionMarkerBottom); + dest.writeParcelable(mCharacterRects, flags); + final float[] matrixArray = new float[9]; + mMatrix.getValues(matrixArray); + dest.writeFloatArray(matrixArray); + } + + @Override + public int hashCode(){ + // TODO: Improve the hash function. + final float floatHash = mSelectionStart + mSelectionEnd + mCandidatesStart + mCandidatesEnd + + mInsertionMarkerHorizontal + mInsertionMarkerTop + mInsertionMarkerBaseline + + mInsertionMarkerBottom; + int hash = floatHash > 0 ? (int) floatHash : (int)(-floatHash); + if (mCharacterRects != null) { + hash += mCharacterRects.hashCode(); + } + hash += mMatrix.hashCode(); + return hash; + } + + @Override + public boolean equals(Object obj){ + if (obj == null) { + return false; + } + if (this == obj) { + return true; + } + if (!(obj instanceof CursorAnchorInfo)) { + return false; + } + final CursorAnchorInfo that = (CursorAnchorInfo) obj; + if (hashCode() != that.hashCode()) { + return false; + } + if (mSelectionStart != that.mSelectionStart + || mSelectionEnd != that.mSelectionEnd + || mCandidatesStart != that.mCandidatesStart + || mCandidatesEnd != that.mCandidatesEnd) { + return false; + } + if (!Objects.equals(mCharacterRects, that.mCharacterRects)) { + return false; + } + if (!Objects.equals(mMatrix, that.mMatrix)) { + return false; + } + return true; + } + + @Override + public String toString() { + return "SelectionInfo{mSelection=" + mSelectionStart + "," + mSelectionEnd + + " mCandiadtes=" + mCandidatesStart + "," + mCandidatesEnd + + " mInsertionMarkerHorizontal=" + mInsertionMarkerHorizontal + + " mInsertionMarkerTop=" + mInsertionMarkerTop + + " mInsertionMarkerBaseline=" + mInsertionMarkerBaseline + + " mInsertionMarkerBottom=" + mInsertionMarkerBottom + + " mCharacterRects=" + (mCharacterRects != null ? mCharacterRects : "null") + + " mMatrix=" + mMatrix + + "}"; + } + + /** + * Builder for {@link CursorAnchorInfo}. This class is not designed to be thread-safe. + */ + public static final class CursorAnchorInfoBuilder { + /** + * Sets the text range of the selection. Calling this can be skipped if there is no + * selection. + */ + public CursorAnchorInfoBuilder setSelectionRange(final int newStart, final int newEnd) { + mSelectionStart = newStart; + mSelectionEnd = newEnd; + return this; + } + private int mSelectionStart = -1; + private int mSelectionEnd = -1; + + /** + * Sets the text range of the composition string. Calling this can be skipped if there is + * no composition. + */ + public CursorAnchorInfoBuilder setCandidateRange(final int start, final int end) { + mCandidateStart = start; + mCandidateEnd = end; + return this; + } + private int mCandidateStart = -1; + private int mCandidateEnd = -1; + + /** + * Sets the location of the text insertion point (zero width cursor) as a rectangle in + * local coordinates. Calling this can be skipped when there is no text insertion point; + * however if there is an insertion point, editors must call this method. + * @param horizontalPosition horizontal position of the insertion marker, in the local + * coordinates that will be transformed with the transformation matrix when rendered on the + * screen. This should be calculated or compatible with + * {@link Layout#getPrimaryHorizontal(int)}. + * @param lineTop vertical position of the insertion marker, in the local coordinates that + * will be transformed with the transformation matrix when rendered on the screen. This + * should be calculated or compatible with {@link Layout#getLineTop(int)}. + * @param lineBaseline vertical position of the insertion marker, in the local coordinates + * that will be transformed with the transformation matrix when rendered on the screen. This + * should be calculated or compatible with {@link Layout#getLineBaseline(int)}. + * @param lineBottom vertical position of the insertion marker, in the local coordinates + * that will be transformed with the transformation matrix when rendered on the screen. This + * should be calculated or compatible with {@link Layout#getLineBottom(int)}. + */ + public CursorAnchorInfoBuilder setInsertionMarkerLocation( + final float horizontalPosition, final float lineTop, final float lineBaseline, + final float lineBottom){ + mInsertionMarkerHorizontal = horizontalPosition; + mInsertionMarkerTop = lineTop; + mInsertionMarkerBaseline = lineBaseline; + mInsertionMarkerBottom = lineBottom; + return this; + } + private float mInsertionMarkerHorizontal = Float.NaN; + private float mInsertionMarkerTop = Float.NaN; + private float mInsertionMarkerBaseline = Float.NaN; + private float mInsertionMarkerBottom = Float.NaN; + + /** + * Adds the bounding box of the character specified with the index. + * <p> + * Editor authors should not call this method for characters that are invisible. + * </p> + * + * @param index index of the character in Java chars units. Must be specified in + * ascending order across successive calls. + * @param leadingEdgeX x coordinate of the leading edge of the character in local + * coordinates, that is, left edge for LTR text and right edge for RTL text. + * @param leadingEdgeY y coordinate of the leading edge of the character in local + * coordinates. + * @param trailingEdgeX x coordinate of the trailing edge of the character in local + * coordinates, that is, right edge for LTR text and left edge for RTL text. + * @param trailingEdgeY y coordinate of the trailing edge of the character in local + * coordinates. + * @throws IllegalArgumentException If the index is a negative value, or not greater than + * all of the previously called indices. + */ + public CursorAnchorInfoBuilder addCharacterRect(final int index, + final float leadingEdgeX, final float leadingEdgeY, final float trailingEdgeX, + final float trailingEdgeY) { + if (index < 0) { + throw new IllegalArgumentException("index must not be a negative integer."); + } + if (mCharacterRectBuilder == null) { + mCharacterRectBuilder = new SparseRectFArrayBuilder(); + } + mCharacterRectBuilder.append(index, leadingEdgeX, leadingEdgeY, trailingEdgeX, + trailingEdgeY); + return this; + } + private SparseRectFArrayBuilder mCharacterRectBuilder = null; + + /** + * Sets the matrix that transforms local coordinates into screen coordinates. + * @param matrix transformation matrix from local coordinates into screen coordinates. null + * is interpreted as an identity matrix. + */ + public CursorAnchorInfoBuilder setMatrix(final Matrix matrix) { + if (matrix != null) { + mMatrix = matrix; + } else { + mMatrix = Matrix.IDENTITY_MATRIX; + } + return this; + } + private Matrix mMatrix = Matrix.IDENTITY_MATRIX; + + /** + * @return {@link CursorAnchorInfo} using parameters in this + * {@link CursorAnchorInfoBuilder}. + */ + public CursorAnchorInfo build() { + return new CursorAnchorInfo(this); + } + + /** + * Resets the internal state so that this instance can be reused to build another + * instance of {@link CursorAnchorInfo}. + */ + public void reset() { + mSelectionStart = -1; + mSelectionEnd = -1; + mCandidateStart = -1; + mCandidateEnd = -1; + mInsertionMarkerHorizontal = Float.NaN; + mInsertionMarkerTop = Float.NaN; + mInsertionMarkerBaseline = Float.NaN; + mInsertionMarkerBottom = Float.NaN; + mMatrix = Matrix.IDENTITY_MATRIX; + if (mCharacterRectBuilder != null) { + mCharacterRectBuilder.reset(); + } + } + } + + private CursorAnchorInfo(final CursorAnchorInfoBuilder builder) { + mSelectionStart = builder.mSelectionStart; + mSelectionEnd = builder.mSelectionEnd; + mCandidatesStart = builder.mCandidateStart; + mCandidatesEnd = builder.mCandidateEnd; + mInsertionMarkerHorizontal = builder.mInsertionMarkerHorizontal; + mInsertionMarkerTop = builder.mInsertionMarkerTop; + mInsertionMarkerBaseline = builder.mInsertionMarkerBaseline; + mInsertionMarkerBottom = builder.mInsertionMarkerBottom; + mCharacterRects = builder.mCharacterRectBuilder != null ? + builder.mCharacterRectBuilder.build() : null; + mMatrix = builder.mMatrix; + } + + /** + * Returns the index where the selection starts. + * @return -1 if there is no selection. + */ + public int getSelectionStart() { + return mSelectionStart; + } + + /** + * Returns the index where the selection ends. + * @return -1 if there is no selection. + */ + public int getSelectionEnd() { + return mSelectionEnd; + } + + /** + * Returns the index where the composition starts. + * @return -1 if there is no composition. + */ + public int getCandidatesStart() { + return mCandidatesStart; + } + + /** + * Returns the index where the composition ends. + * @return -1 if there is no composition. + */ + public int getCandidatesEnd() { + return mCandidatesEnd; + } + + /** + * Returns the horizontal start of the insertion marker, in the local coordinates that will + * be transformed with {@link #getMatrix()} when rendered on the screen. + * @return x coordinate that is compatible with {@link Layout#getPrimaryHorizontal(int)}. + * Pay special care to RTL/LTR handling. + * {@code java.lang.Float.NaN} if not specified. + * @see Layout#getPrimaryHorizontal(int) + */ + public float getInsertionMarkerHorizontal() { + return mInsertionMarkerHorizontal; + } + /** + * Returns the vertical top position of the insertion marker, in the local coordinates that + * will be transformed with {@link #getMatrix()} when rendered on the screen. + * @return y coordinate that is compatible with {@link Layout#getLineTop(int)}. + * {@code java.lang.Float.NaN} if not specified. + */ + public float getInsertionMarkerTop() { + return mInsertionMarkerTop; + } + /** + * Returns the vertical baseline position of the insertion marker, in the local coordinates + * that will be transformed with {@link #getMatrix()} when rendered on the screen. + * @return y coordinate that is compatible with {@link Layout#getLineBaseline(int)}. + * {@code java.lang.Float.NaN} if not specified. + */ + public float getInsertionMarkerBaseline() { + return mInsertionMarkerBaseline; + } + /** + * Returns the vertical bottom position of the insertion marker, in the local coordinates + * that will be transformed with {@link #getMatrix()} when rendered on the screen. + * @return y coordinate that is compatible with {@link Layout#getLineBottom(int)}. + * {@code java.lang.Float.NaN} if not specified. + */ + public float getInsertionMarkerBottom() { + return mInsertionMarkerBottom; + } + + /** + * Returns a new instance of {@link RectF} that indicates the location of the character + * specified with the index. + * <p> + * Note that coordinates are not necessarily contiguous or even monotonous, especially when + * RTL text and LTR text are mixed. + * </p> + * @param index index of the character in a Java chars. + * @return a new instance of {@link RectF} that represents the location of the character in + * local coordinates. null if the character is invisible or the application did not provide + * the location. Note that the {@code left} field can be greater than the {@code right} field + * if the character is in RTL text. + */ + // TODO: Prepare a document about the expected behavior for surrogate pairs, combining + // characters, and non-graphical chars. + public RectF getCharacterRect(final int index) { + if (mCharacterRects == null) { + return null; + } + return mCharacterRects.get(index); + } + + /** + * Returns a new instance of {@link android.graphics.Matrix} that indicates the transformation + * matrix that is to be applied other positional data in this class. + * @return a new instance (copy) of the transformation matrix. + */ + public Matrix getMatrix() { + return new Matrix(mMatrix); + } + + /** + * Used to make this class parcelable. + */ + public static final Parcelable.Creator<CursorAnchorInfo> CREATOR + = new Parcelable.Creator<CursorAnchorInfo>() { + @Override + public CursorAnchorInfo createFromParcel(Parcel source) { + return new CursorAnchorInfo(source); + } + + @Override + public CursorAnchorInfo[] newArray(int size) { + return new CursorAnchorInfo[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 0227873..e1c6f52 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -49,6 +49,7 @@ import android.view.InputEventSender; import android.view.KeyEvent; import android.view.View; import android.view.ViewRootImpl; +import android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -321,6 +322,7 @@ public final class InputMethodManager { * The buffer to retrieve the view location in screen coordinates in {@link #updateCursor}. */ private final int[] mViewTopLeft = new int[2]; + private final CursorAnchorInfoBuilder mCursorAnchorInfoBuilder = new CursorAnchorInfoBuilder(); // ----------------------------------------------------------- @@ -1435,7 +1437,7 @@ public final class InputMethodManager { || mCurrentTextBoxAttribute == null || mCurMethod == null) { return; } - + if (mCursorSelStart != selStart || mCursorSelEnd != selEnd || mCursorCandStart != candidatesStart || mCursorCandEnd != candidatesEnd) { @@ -1556,6 +1558,31 @@ public final class InputMethodManager { } /** + * Report positional change of the text insertion point and/or characters in the composition + * string. + */ + public void updateCursorAnchorInfo(View view, final CursorAnchorInfo cursorAnchorInfo) { + if (view == null || cursorAnchorInfo == null) { + return; + } + checkFocus(); + synchronized (mH) { + if ((mServedView != view && + (mServedView == null || !mServedView.checkInputConnectionProxy(view))) + || mCurrentTextBoxAttribute == null || mCurMethod == null) { + return; + } + if (DEBUG) Log.d(TAG, "updateCursorAnchorInfo"); + + try { + mCurMethod.updateCursorAnchorInfo(cursorAnchorInfo); + } catch (RemoteException e) { + Log.w(TAG, "IME died: " + mCurId, e); + } + } + } + + /** * Call {@link InputMethodSession#appPrivateCommand(String, Bundle) * InputMethodSession.appPrivateCommand()} on the current Input Method. * @param view Optional View that is sending the command, or null if diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java index 6386299..74fbbc7 100644 --- a/core/java/android/view/inputmethod/InputMethodSession.java +++ b/core/java/android/view/inputmethod/InputMethodSession.java @@ -165,7 +165,7 @@ public interface InputMethodSession { public void appPrivateCommand(String action, Bundle data); /** - * Toggle the soft input window. + * Toggle the soft input window. * Applications can toggle the state of the soft input window. * @param showFlags Provides additional operating flags. May be * 0 or have the {@link InputMethodManager#SHOW_IMPLICIT}, @@ -175,4 +175,14 @@ public interface InputMethodSession { * {@link InputMethodManager#HIDE_NOT_ALWAYS} bit set. */ public void toggleSoftInput(int showFlags, int hideFlags); + + /** + * This method is called when the cursor and/or the character position relevant to text input + * is changed on the screen. This is not called by default. It will only be reported if + * requested by the input method. + * + * @param cursorAnchorInfo Positional information relevant to text input, such as text + * insertion point and composition string. + */ + public void updateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo); } diff --git a/core/java/android/view/inputmethod/SparseRectFArray.java b/core/java/android/view/inputmethod/SparseRectFArray.java new file mode 100644 index 0000000..40cade7 --- /dev/null +++ b/core/java/android/view/inputmethod/SparseRectFArray.java @@ -0,0 +1,265 @@ +/* + * 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. + */ + +package android.view.inputmethod; + +import android.graphics.RectF; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Arrays; + +/** + * An implementation of SparseArray specialized for {@link android.graphics.RectF}. + * <p> + * As this is a sparse array, it represents an array of {@link RectF} most of which are null. This + * class could be in some other packages like android.graphics or android.util but currently + * belong to android.view.inputmethod because this class is hidden and used only in input method + * framework. + * </p> + * @hide + */ +public final class SparseRectFArray implements Parcelable { + /** + * The keys, in ascending order, of those {@link RectF} that are not null. For example, + * {@code [null, null, null, Rect1, null, Rect2]} would be represented by {@code [3,5]}. + * @see #mCoordinates + */ + private final int[] mKeys; + + /** + * Stores coordinates of the rectangles, in the order of + * {@code rects[mKeys[0]].left}, {@code rects[mKeys[0]].top}, + * {@code rects[mKeys[0]].right}, {@code rects[mKeys[0]].bottom}, + * {@code rects[mKeys[1]].left}, {@code rects[mKeys[1]].top}, + * {@code rects[mKeys[1]].right}, {@code rects[mKeys[1]].bottom}, + * {@code rects[mKeys[2]].left}, {@code rects[mKeys[2]].top}, .... + */ + private final float[] mCoordinates; + + public SparseRectFArray(final Parcel source) { + mKeys = source.createIntArray(); + mCoordinates = source.createFloatArray(); + } + + /** + * Used to package this object into a {@link Parcel}. + * + * @param dest The {@link Parcel} to be written. + * @param flags The flags used for parceling. + */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeIntArray(mKeys); + dest.writeFloatArray(mCoordinates); + } + + @Override + public int hashCode() { + // TODO: Improve the hash function. + if (mKeys == null || mKeys.length == 0) { + return 0; + } + int hash = mKeys.length; + // For performance reasons, only the first rectangle is used for the hash code now. + for (int i = 0; i < 4; i++) { + hash *= 31; + hash += mCoordinates[i]; + } + return hash; + } + + @Override + public boolean equals(Object obj){ + if (obj == null) { + return false; + } + if (this == obj) { + return true; + } + if (!(obj instanceof SparseRectFArray)) { + return false; + } + final SparseRectFArray that = (SparseRectFArray) obj; + + return Arrays.equals(mKeys, that.mKeys) && Arrays.equals(mCoordinates, that.mCoordinates); + } + + @Override + public String toString() { + if (mKeys == null || mCoordinates == null) { + return "SparseRectFArray{}"; + } + final StringBuilder sb = new StringBuilder(); + sb.append("SparseRectFArray{"); + for (int i = 0; i < mKeys.length; i++) { + if (i != 0) { + sb.append(", "); + } + final int baseIndex = i * 4; + sb.append(mKeys[i]); + sb.append(":["); + sb.append(mCoordinates[baseIndex + 0]); + sb.append(","); + sb.append(mCoordinates[baseIndex + 1]); + sb.append("],["); + sb.append(mCoordinates[baseIndex + 2]); + sb.append(","); + sb.append(mCoordinates[baseIndex + 3]); + sb.append("]"); + } + sb.append("}"); + return sb.toString(); + } + + /** + * Builder for {@link SparseRectFArray}. This class is not designed to be thread-safe. + * @hide + */ + public static final class SparseRectFArrayBuilder { + /** + * Throws {@link IllegalArgumentException} to make sure that this class is correctly used. + * @param key key to be checked. + */ + private void checkIndex(final int key) { + if (mCount == 0) { + return; + } + if (mKeys[mCount - 1] >= key) { + throw new IllegalArgumentException("key must be greater than all existing keys."); + } + } + + /** + * Extends the internal array if necessary. + */ + private void ensureBufferSize() { + if (mKeys == null) { + mKeys = new int[INITIAL_SIZE]; + } + if (mCoordinates == null) { + mCoordinates = new float[INITIAL_SIZE * 4]; + } + final int requiredIndexArraySize = mCount + 1; + if (mKeys.length <= requiredIndexArraySize) { + final int[] newArray = new int[requiredIndexArraySize * 2]; + System.arraycopy(mKeys, 0, newArray, 0, mCount); + mKeys = newArray; + } + final int requiredCoordinatesArraySize = (mCount + 1) * 4; + if (mCoordinates.length <= requiredCoordinatesArraySize) { + final float[] newArray = new float[requiredCoordinatesArraySize * 2]; + System.arraycopy(mCoordinates, 0, newArray, 0, mCount * 4); + mCoordinates = newArray; + } + } + + /** + * Puts the rectangle with an integer key. + * @param key the key to be associated with the rectangle. It must be greater than all + * existing keys that have been previously specified. + * @param left left of the rectangle. + * @param top top of the rectangle. + * @param right right of the rectangle. + * @param bottom bottom of the rectangle. + * @return the receiver object itself for chaining method calls. + * @throws IllegalArgumentException If the index is not greater than all of existing keys. + */ + public SparseRectFArrayBuilder append(final int key, + final float left, final float top, final float right, final float bottom) { + checkIndex(key); + ensureBufferSize(); + final int baseCoordinatesIndex = mCount * 4; + mCoordinates[baseCoordinatesIndex + 0] = left; + mCoordinates[baseCoordinatesIndex + 1] = top; + mCoordinates[baseCoordinatesIndex + 2] = right; + mCoordinates[baseCoordinatesIndex + 3] = bottom; + mKeys[mCount] = key; + ++mCount; + return this; + } + private int mCount = 0; + private int[] mKeys = null; + private float[] mCoordinates = null; + private static int INITIAL_SIZE = 16; + + /** + * @return {@link SparseRectFArray} using parameters in this {@link SparseRectFArray}. + */ + public SparseRectFArray build() { + return new SparseRectFArray(this); + } + + public void reset() { + if (mCount == 0) { + mKeys = null; + mCoordinates = null; + } + mCount = 0; + } + } + + private SparseRectFArray(final SparseRectFArrayBuilder builder) { + if (builder.mCount == 0) { + mKeys = null; + mCoordinates = null; + } else { + mKeys = new int[builder.mCount]; + mCoordinates = new float[builder.mCount * 4]; + System.arraycopy(builder.mKeys, 0, mKeys, 0, builder.mCount); + System.arraycopy(builder.mCoordinates, 0, mCoordinates, 0, builder.mCount * 4); + } + } + + public RectF get(final int index) { + if (mKeys == null) { + return null; + } + if (index < 0) { + return null; + } + final int arrayIndex = Arrays.binarySearch(mKeys, index); + if (arrayIndex < 0) { + return null; + } + final int baseCoordIndex = arrayIndex * 4; + return new RectF(mCoordinates[baseCoordIndex], + mCoordinates[baseCoordIndex + 1], + mCoordinates[baseCoordIndex + 2], + mCoordinates[baseCoordIndex + 3]); + } + + /** + * Used to make this class parcelable. + */ + public static final Parcelable.Creator<SparseRectFArray> CREATOR = + new Parcelable.Creator<SparseRectFArray>() { + @Override + public SparseRectFArray createFromParcel(Parcel source) { + return new SparseRectFArray(source); + } + @Override + public SparseRectFArray[] newArray(int size) { + return new SparseRectFArray[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } +} + diff --git a/core/java/android/webkit/EventLogTags.logtags b/core/java/android/webkit/EventLogTags.logtags index b0b5493..a90aebd 100644 --- a/core/java/android/webkit/EventLogTags.logtags +++ b/core/java/android/webkit/EventLogTags.logtags @@ -8,3 +8,4 @@ option java_package android.webkit; # 70103- used by the browser app itself 70150 browser_snap_center +70151 exp_det_attempt_to_call_object_getclass (app_signature|3) diff --git a/core/java/android/webkit/PermissionRequest.java b/core/java/android/webkit/PermissionRequest.java index 3e33498..fa760b7 100644 --- a/core/java/android/webkit/PermissionRequest.java +++ b/core/java/android/webkit/PermissionRequest.java @@ -28,6 +28,7 @@ import android.net.Uri; public interface PermissionRequest { /** * Resource belongs to geolocation service. + * @hide - see b/14668406 */ public final static long RESOURCE_GEOLOCATION = 1 << 0; /** diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java index cde8080..99a7886 100644 --- a/core/java/android/widget/ShareActionProvider.java +++ b/core/java/android/widget/ShareActionProvider.java @@ -276,6 +276,13 @@ public class ShareActionProvider extends ActionProvider { * @see Intent#ACTION_SEND_MULTIPLE */ public void setShareIntent(Intent shareIntent) { + if (shareIntent != null) { + final String action = shareIntent.getAction(); + if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) { + shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | + Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS); + } + } ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName); dataModel.setIntent(shareIntent); @@ -292,7 +299,12 @@ public class ShareActionProvider extends ActionProvider { final int itemId = item.getItemId(); Intent launchIntent = dataModel.chooseActivity(itemId); if (launchIntent != null) { - launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); + final String action = launchIntent.getAction(); + if (Intent.ACTION_SEND.equals(action) || + Intent.ACTION_SEND_MULTIPLE.equals(action)) { + launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | + Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS); + } mContext.startActivity(launchIntent); } return true; @@ -308,7 +320,7 @@ public class ShareActionProvider extends ActionProvider { return; } if (mOnChooseActivityListener == null) { - mOnChooseActivityListener = new ShareAcitivityChooserModelPolicy(); + mOnChooseActivityListener = new ShareActivityChooserModelPolicy(); } ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName); dataModel.setOnChooseActivityListener(mOnChooseActivityListener); @@ -317,7 +329,7 @@ public class ShareActionProvider extends ActionProvider { /** * Policy that delegates to the {@link OnShareTargetSelectedListener}, if such. */ - private class ShareAcitivityChooserModelPolicy implements OnChooseActivityListener { + private class ShareActivityChooserModelPolicy implements OnChooseActivityListener { @Override public boolean onChooseActivity(ActivityChooserModel host, Intent intent) { if (mOnShareTargetSelectedListener != null) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index b91111d..8f073de 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -289,6 +289,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance(); private float mShadowRadius, mShadowDx, mShadowDy; + private int mShadowColor; + private boolean mPreDrawRegistered; @@ -2755,6 +2757,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mShadowRadius = radius; mShadowDx = dx; mShadowDy = dy; + mShadowColor = color; // Will change text clip region if (mEditor != null) mEditor.invalidateTextDisplayList(); @@ -2804,7 +2807,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @attr ref android.R.styleable#TextView_shadowColor */ public int getShadowColor() { - return mTextPaint.shadowColor; + return mShadowColor; } /** diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 1eda373..106ac0b 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -33,6 +33,14 @@ public class ChooserActivity extends ResolverActivity { return; } Intent target = (Intent)targetParcelable; + if (target != null) { + final String action = target.getAction(); + if (Intent.ACTION_SEND.equals(action) || + Intent.ACTION_SEND_MULTIPLE.equals(action)) { + target.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | + Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS); + } + } CharSequence title = intent.getCharSequenceExtra(Intent.EXTRA_TITLE); if (title == null) { title = getResources().getText(com.android.internal.R.string.chooseActivity); @@ -43,13 +51,19 @@ public class ChooserActivity extends ResolverActivity { initialIntents = new Intent[pa.length]; for (int i=0; i<pa.length; i++) { if (!(pa[i] instanceof Intent)) { - Log.w("ChooserActivity", "Initial intent #" + i - + " not an Intent: " + pa[i]); + Log.w("ChooserActivity", "Initial intent #" + i + " not an Intent: " + pa[i]); finish(); super.onCreate(null); return; } - initialIntents[i] = (Intent)pa[i]; + final Intent in = (Intent) pa[i]; + final String action = in.getAction(); + if (Intent.ACTION_SEND.equals(action) || + Intent.ACTION_SEND_MULTIPLE.equals(action)) { + in.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | + Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS); + } + initialIntents[i] = in; } } super.onCreate(savedInstanceState, target, title, initialIntents, null, false); diff --git a/core/java/com/android/internal/app/IUsageStats.aidl b/core/java/com/android/internal/app/IUsageStats.aidl index 1ea7409..7e7f0e1 100644 --- a/core/java/com/android/internal/app/IUsageStats.aidl +++ b/core/java/com/android/internal/app/IUsageStats.aidl @@ -16,13 +16,17 @@ package com.android.internal.app; +import android.app.UsageStats; import android.content.ComponentName; -import com.android.internal.os.PkgUsageStats; +import android.content.res.Configuration; +import android.os.ParcelableParcel; interface IUsageStats { void noteResumeComponent(in ComponentName componentName); void notePauseComponent(in ComponentName componentName); void noteLaunchTime(in ComponentName componentName, int millis); - PkgUsageStats getPkgUsageStats(in ComponentName componentName); - PkgUsageStats[] getAllPkgUsageStats(); + void noteStartConfig(in Configuration config); + UsageStats.PackageStats getPkgUsageStats(String callingPkg, in ComponentName componentName); + UsageStats.PackageStats[] getAllPkgUsageStats(String callingPkg); + ParcelableParcel getCurrentStats(String callingPkg); } diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java index 8cdaf91..abd1791 100644 --- a/core/java/com/android/internal/app/PlatLogoActivity.java +++ b/core/java/com/android/internal/app/PlatLogoActivity.java @@ -18,156 +18,122 @@ package com.android.internal.app; import android.app.Activity; import android.content.ActivityNotFoundException; +import android.content.ContentResolver; +import android.content.Context; import android.content.Intent; +import android.graphics.Color; import android.graphics.Typeface; -import android.provider.Settings; import android.os.Build; import android.os.Bundle; -import android.os.Handler; -import android.text.method.AllCapsTransformationMethod; +import android.provider.Settings; +import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.Gravity; import android.view.View; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.AnticipateOvershootInterpolator; -import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; -import android.widget.ImageView; import android.widget.TextView; public class PlatLogoActivity extends Activity { - FrameLayout mContent; - int mCount; - final Handler mHandler = new Handler(); - static final int BGCOLOR = 0xffed1d24; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - DisplayMetrics metrics = new DisplayMetrics(); - getWindowManager().getDefaultDisplay().getMetrics(metrics); - - Typeface bold = Typeface.create("sans-serif", Typeface.BOLD); - Typeface light = Typeface.create("sans-serif-light", Typeface.NORMAL); - - mContent = new FrameLayout(this); - mContent.setBackgroundColor(0xC0000000); - - final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.WRAP_CONTENT, - FrameLayout.LayoutParams.WRAP_CONTENT); - lp.gravity = Gravity.CENTER; - - final ImageView logo = new ImageView(this); - logo.setImageResource(com.android.internal.R.drawable.platlogo); - logo.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - logo.setVisibility(View.INVISIBLE); - - final View bg = new View(this); - bg.setBackgroundColor(BGCOLOR); - bg.setAlpha(0f); - - final TextView letter = new TextView(this); - - letter.setTypeface(bold); - letter.setTextSize(300); - letter.setTextColor(0xFFFFFFFF); - letter.setGravity(Gravity.CENTER); - letter.setText(String.valueOf(Build.ID).substring(0, 1)); - - final int p = (int)(4 * metrics.density); - - final TextView tv = new TextView(this); - if (light != null) tv.setTypeface(light); - tv.setTextSize(30); - tv.setPadding(p, p, p, p); - tv.setTextColor(0xFFFFFFFF); - tv.setGravity(Gravity.CENTER); - tv.setTransformationMethod(new AllCapsTransformationMethod(this)); - tv.setText("Android " + Build.VERSION.RELEASE); - tv.setVisibility(View.INVISIBLE); - - mContent.addView(bg); - mContent.addView(letter, lp); - mContent.addView(logo, lp); + private static class Torso extends FrameLayout { + boolean mAnimate = false; + TextView mText; + + public Torso(Context context) { + this(context, null); + } + public Torso(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + public Torso(Context context, AttributeSet attrs, int flags) { + super(context, attrs, flags); + + for (int i=0; i<2; i++) { + final View v = new View(context); + v.setBackgroundColor(i % 2 == 0 ? Color.BLUE : Color.RED); + addView(v); + } - final FrameLayout.LayoutParams lp2 = new FrameLayout.LayoutParams(lp); - lp2.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; - lp2.bottomMargin = 10*p; + mText = new TextView(context); + mText.setTextColor(Color.BLACK); + mText.setTextSize(14 /* sp */); + mText.setTypeface(Typeface.create("monospace", Typeface.BOLD)); - mContent.addView(tv, lp2); + addView(mText, new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.WRAP_CONTENT, + Gravity.BOTTOM | Gravity.LEFT + )); + } - mContent.setOnClickListener(new View.OnClickListener() { - int clicks; + private Runnable mRunnable = new Runnable() { @Override - public void onClick(View v) { - clicks++; - if (clicks >= 6) { - mContent.performLongClick(); - return; + public void run() { + mText.setText(String.format("android_%s.flv - build %s", + Build.VERSION.CODENAME, + Build.VERSION.INCREMENTAL)); + final int N = getChildCount(); + final float parentw = getMeasuredWidth(); + final float parenth = getMeasuredHeight(); + for (int i=0; i<N; i++) { + final View v = getChildAt(i); + if (v instanceof TextView) continue; + + final int w = (int) (Math.random() * parentw); + final int h = (int) (Math.random() * parenth); + v.setLayoutParams(new FrameLayout.LayoutParams(w, h)); + + v.setX((float) Math.random() * (parentw - w)); + v.setY((float) Math.random() * (parenth - h)); } - letter.animate().cancel(); - final float offset = (int)letter.getRotation() % 360; - letter.animate() - .rotationBy((Math.random() > 0.5f ? 360 : -360) - offset) - .setInterpolator(new DecelerateInterpolator()) - .setDuration(700).start(); - } - }); - mContent.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - if (logo.getVisibility() != View.VISIBLE) { - bg.setScaleX(0.01f); - bg.animate().alpha(1f).scaleX(1f).setStartDelay(500).start(); - letter.animate().alpha(0f).scaleY(0.5f).scaleX(0.5f) - .rotationBy(360) - .setInterpolator(new AccelerateInterpolator()) - .setDuration(1000) - .start(); - logo.setAlpha(0f); - logo.setVisibility(View.VISIBLE); - logo.setScaleX(0.5f); - logo.setScaleY(0.5f); - logo.animate().alpha(1f).scaleX(1f).scaleY(1f) - .setDuration(1000).setStartDelay(500) - .setInterpolator(new AnticipateOvershootInterpolator()) - .start(); - tv.setAlpha(0f); - tv.setVisibility(View.VISIBLE); - tv.animate().alpha(1f).setDuration(1000).setStartDelay(1000).start(); - return true; - } - return false; + if (mAnimate) postDelayed(this, 1000); } - }); + }; + @Override + protected void onAttachedToWindow() { + mAnimate = true; + post(mRunnable); + } + @Override + protected void onDetachedFromWindow() { + mAnimate = false; + removeCallbacks(mRunnable); + } + } - logo.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - if (Settings.System.getLong(getContentResolver(), Settings.System.EGG_MODE, 0) - == 0) { - // For posterity: the moment this user unlocked the easter egg - Settings.System.putLong(getContentResolver(), - Settings.System.EGG_MODE, - System.currentTimeMillis()); - } - try { - startActivity(new Intent(Intent.ACTION_MAIN) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_CLEAR_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) - .addCategory("com.android.internal.category.PLATLOGO")); - } catch (ActivityNotFoundException ex) { - android.util.Log.e("PlatLogoActivity", "Couldn't catch a break."); - } - finish(); - return true; - } - }); - - setContentView(mContent); + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final Torso t = new Torso(this); + t.setBackgroundColor(Color.WHITE); + + t.getChildAt(0) + .setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + final ContentResolver cr = getContentResolver(); + if (Settings.System.getLong(cr, Settings.System.EGG_MODE, 0) + == 0) { + // For posterity: the moment this user unlocked the easter egg + Settings.System.putLong(cr, + Settings.System.EGG_MODE, + System.currentTimeMillis()); + } + try { + startActivity(new Intent(Intent.ACTION_MAIN) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + .addCategory("com.android.internal.category.PLATLOGO")); + } catch (ActivityNotFoundException ex) { + android.util.Log.e("PlatLogoActivity", "Couldn't catch a break."); + } + finish(); + return true; + } + }); + + setContentView(t); } } diff --git a/core/java/com/android/internal/os/PkgUsageStats.java b/core/java/com/android/internal/os/PkgUsageStats.java deleted file mode 100644 index 8c2c405..0000000 --- a/core/java/com/android/internal/os/PkgUsageStats.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.os; - -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.HashMap; -import java.util.Map; - -/** - * implementation of PkgUsageStats associated with an - * application package. - * @hide - */ -public class PkgUsageStats implements Parcelable { - public String packageName; - public int launchCount; - public long usageTime; - public Map<String, Long> componentResumeTimes; - - public static final Parcelable.Creator<PkgUsageStats> CREATOR - = new Parcelable.Creator<PkgUsageStats>() { - public PkgUsageStats createFromParcel(Parcel in) { - return new PkgUsageStats(in); - } - - public PkgUsageStats[] newArray(int size) { - return new PkgUsageStats[size]; - } - }; - - public String toString() { - return "PkgUsageStats{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + packageName + "}"; - } - - public PkgUsageStats(String pkgName, int count, long time, Map<String, Long> lastResumeTimes) { - packageName = pkgName; - launchCount = count; - usageTime = time; - componentResumeTimes = new HashMap<String, Long>(lastResumeTimes); - } - - public PkgUsageStats(Parcel source) { - packageName = source.readString(); - launchCount = source.readInt(); - usageTime = source.readLong(); - final int N = source.readInt(); - componentResumeTimes = new HashMap<String, Long>(N); - for (int i = 0; i < N; i++) { - String component = source.readString(); - long lastResumeTime = source.readLong(); - componentResumeTimes.put(component, lastResumeTime); - } - } - - public PkgUsageStats(PkgUsageStats pStats) { - packageName = pStats.packageName; - launchCount = pStats.launchCount; - usageTime = pStats.usageTime; - componentResumeTimes = new HashMap<String, Long>(pStats.componentResumeTimes); - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int parcelableFlags) { - dest.writeString(packageName); - dest.writeInt(launchCount); - dest.writeLong(usageTime); - dest.writeInt(componentResumeTimes.size()); - for (Map.Entry<String, Long> ent : componentResumeTimes.entrySet()) { - dest.writeString(ent.getKey()); - dest.writeLong(ent.getValue()); - } - } -} diff --git a/core/java/com/android/internal/util/LegacyNotificationUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java index 0394bbc..f38cbde 100644 --- a/core/java/com/android/internal/util/LegacyNotificationUtil.java +++ b/core/java/com/android/internal/util/NotificationColorUtil.java @@ -24,6 +24,7 @@ import android.graphics.Color; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.VectorDrawable; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.TextAppearanceSpan; @@ -38,21 +39,21 @@ import java.util.WeakHashMap; * * @hide */ -public class LegacyNotificationUtil { +public class NotificationColorUtil { - private static final String TAG = "LegacyNotificationUtil"; + private static final String TAG = "NotificationColorUtil"; private static final Object sLock = new Object(); - private static LegacyNotificationUtil sInstance; + private static NotificationColorUtil sInstance; private final ImageUtils mImageUtils = new ImageUtils(); private final WeakHashMap<Bitmap, Pair<Boolean, Integer>> mGrayscaleBitmapCache = new WeakHashMap<Bitmap, Pair<Boolean, Integer>>(); - public static LegacyNotificationUtil getInstance() { + public static NotificationColorUtil getInstance() { synchronized (sLock) { if (sInstance == null) { - sInstance = new LegacyNotificationUtil(); + sInstance = new NotificationColorUtil(); } return sInstance; } @@ -107,6 +108,9 @@ public class LegacyNotificationUtil { AnimationDrawable ad = (AnimationDrawable) d; int count = ad.getNumberOfFrames(); return count > 0 && isGrayscale(ad.getFrame(0)); + } else if (d instanceof VectorDrawable) { + // We just assume you're doing the right thing if using vectors + return true; } else { return false; } diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java index b380403..bc92c4a 100644 --- a/core/java/com/android/internal/util/Protocol.java +++ b/core/java/com/android/internal/util/Protocol.java @@ -46,6 +46,8 @@ public class Protocol { public static final int BASE_WIFI_MONITOR = 0x00024000; public static final int BASE_WIFI_MANAGER = 0x00025000; public static final int BASE_WIFI_CONTROLLER = 0x00026000; + public static final int BASE_WIFI_SCANNER = 0x00027000; + public static final int BASE_WIFI_SCANNER_SERVICE = 0x00027100; public static final int BASE_DHCP = 0x00030000; public static final int BASE_DATA_CONNECTION = 0x00040000; public static final int BASE_DATA_CONNECTION_AC = 0x00041000; diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl index 90210ce..367b713 100644 --- a/core/java/com/android/internal/view/IInputMethodSession.aidl +++ b/core/java/com/android/internal/view/IInputMethodSession.aidl @@ -21,6 +21,7 @@ import android.os.Bundle; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.ExtractedText; /** @@ -47,4 +48,6 @@ oneway interface IInputMethodSession { void toggleSoftInput(int showFlags, int hideFlags); void finishSession(); + + void updateCursorAnchorInfo(in CursorAnchorInfo cursorAnchorInfo); } diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java index 674d084..bcfa036 100644 --- a/core/java/com/android/internal/widget/SwipeDismissLayout.java +++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java @@ -35,7 +35,7 @@ import android.widget.FrameLayout; public class SwipeDismissLayout extends FrameLayout { private static final String TAG = "SwipeDismissLayout"; - private static final float DISMISS_MIN_PROGRESS = 0.6f; + private static final float DISMISS_MIN_DRAG_WIDTH_RATIO = .4f; public interface OnDismissedListener { void onDismissed(SwipeDismissLayout layout); @@ -244,7 +244,11 @@ public class SwipeDismissLayout extends FrameLayout { if (!mSwiping) { float deltaX = ev.getRawX() - mDownX; float deltaY = ev.getRawY() - mDownY; - mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < mSlop * 2; + if ((deltaX * deltaX) + (deltaY * deltaY) > mSlop * mSlop) { + mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < mSlop * 2; + } else { + mSwiping = false; + } } } @@ -254,12 +258,7 @@ public class SwipeDismissLayout extends FrameLayout { mVelocityTracker.addMovement(ev); mVelocityTracker.computeCurrentVelocity(1000); - float velocityX = mVelocityTracker.getXVelocity(); - float absVelocityX = Math.abs(velocityX); - float absVelocityY = Math.abs(mVelocityTracker.getYVelocity()); - - if (deltaX > (getWidth() * DISMISS_MIN_PROGRESS) && - absVelocityX < mMinFlingVelocity && + if (deltaX > (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO) && ev.getRawX() >= mLastX) { mDismissed = true; } @@ -267,7 +266,7 @@ public class SwipeDismissLayout extends FrameLayout { // Check if the user tried to undo this. if (mDismissed && mSwiping) { // Check if the user's finger is actually back - if (deltaX < (getWidth() * DISMISS_MIN_PROGRESS)) { + if (deltaX < (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO)) { mDismissed = false; } } |
