diff options
20 files changed, 830 insertions, 78 deletions
diff --git a/Android.mk b/Android.mk index 2d0d1f7462c0..a20798d85172 100644 --- a/Android.mk +++ b/Android.mk @@ -202,6 +202,7 @@ LOCAL_SRC_FILES += \ core/java/android/os/INetworkActivityListener.aidl \ core/java/android/os/INetworkManagementService.aidl \ core/java/android/os/IPermissionController.aidl \ + core/java/android/os/IProcessInfoService.aidl \ core/java/android/os/IPowerManager.aidl \ core/java/android/os/IRemoteCallback.aidl \ core/java/android/os/ISchedulingPolicyService.aidl \ diff --git a/api/current.txt b/api/current.txt index ce01a66e6d95..123d8cc03c12 100644 --- a/api/current.txt +++ b/api/current.txt @@ -529,6 +529,7 @@ package android { field public static final int ellipsize = 16842923; // 0x10100ab field public static final int ems = 16843096; // 0x1010158 field public static final int enabled = 16842766; // 0x101000e + field public static final int end = 16843997; // 0x10104dd field public static final int endColor = 16843166; // 0x101019e field public static final deprecated int endYear = 16843133; // 0x101017d field public static final int enterFadeDuration = 16843532; // 0x101030c @@ -1128,6 +1129,7 @@ package android { field public static final int stackFromBottom = 16843005; // 0x10100fd field public static final int stackViewStyle = 16843838; // 0x101043e field public static final int starStyle = 16842882; // 0x1010082 + field public static final int start = 16843996; // 0x10104dc field public static final int startColor = 16843165; // 0x101019d field public static final int startDelay = 16843746; // 0x10103e2 field public static final int startOffset = 16843198; // 0x10101be @@ -8432,7 +8434,6 @@ package android.content.pm { field public java.lang.String parentActivityName; field public java.lang.String permission; field public int persistableMode; - field public boolean resizeable; field public int screenOrientation; field public int softInputMode; field public java.lang.String targetActivity; @@ -11947,6 +11948,9 @@ package android.graphics.drawable { method public android.graphics.drawable.Drawable findDrawableByLayerId(int); method public android.graphics.drawable.Drawable getDrawable(int); method public int getId(int); + method public int getLayerGravity(int); + method public int getLayerHeight(int); + method public int getLayerWidth(int); method public int getNumberOfLayers(); method public int getOpacity(); method public int getPaddingMode(); @@ -11956,7 +11960,10 @@ package android.graphics.drawable { method public void setColorFilter(android.graphics.ColorFilter); method public boolean setDrawableByLayerId(int, android.graphics.drawable.Drawable); method public void setId(int, int); + method public void setLayerGravity(int, int); method public void setLayerInset(int, int, int, int, int); + method public void setLayerInsetRelative(int, int, int, int, int); + method public void setLayerSize(int, int, int); method public void setOpacity(int); method public void setPaddingMode(int); method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable); diff --git a/api/system-current.txt b/api/system-current.txt index dfe429851ca4..6224dfb44e9e 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -601,6 +601,7 @@ package android { field public static final int ellipsize = 16842923; // 0x10100ab field public static final int ems = 16843096; // 0x1010158 field public static final int enabled = 16842766; // 0x101000e + field public static final int end = 16843997; // 0x10104dd field public static final int endColor = 16843166; // 0x101019e field public static final deprecated int endYear = 16843133; // 0x101017d field public static final int enterFadeDuration = 16843532; // 0x101030c @@ -1204,6 +1205,7 @@ package android { field public static final int stackFromBottom = 16843005; // 0x10100fd field public static final int stackViewStyle = 16843838; // 0x101043e field public static final int starStyle = 16842882; // 0x1010082 + field public static final int start = 16843996; // 0x10104dc field public static final int startColor = 16843165; // 0x101019d field public static final int startDelay = 16843746; // 0x10103e2 field public static final int startOffset = 16843198; // 0x10101be @@ -8640,7 +8642,6 @@ package android.content.pm { field public java.lang.String parentActivityName; field public java.lang.String permission; field public int persistableMode; - field public boolean resizeable; field public int screenOrientation; field public int softInputMode; field public java.lang.String targetActivity; @@ -12215,6 +12216,9 @@ package android.graphics.drawable { method public android.graphics.drawable.Drawable findDrawableByLayerId(int); method public android.graphics.drawable.Drawable getDrawable(int); method public int getId(int); + method public int getLayerGravity(int); + method public int getLayerHeight(int); + method public int getLayerWidth(int); method public int getNumberOfLayers(); method public int getOpacity(); method public int getPaddingMode(); @@ -12224,7 +12228,10 @@ package android.graphics.drawable { method public void setColorFilter(android.graphics.ColorFilter); method public boolean setDrawableByLayerId(int, android.graphics.drawable.Drawable); method public void setId(int, int); + method public void setLayerGravity(int, int); method public void setLayerInset(int, int, int, int, int); + method public void setLayerInsetRelative(int, int, int, int, int); + method public void setLayerSize(int, int, int); method public void setOpacity(int); method public void setPaddingMode(int); method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 7a636dbdb59d..c6ffef64f7e8 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -256,6 +256,9 @@ public class ActivityManager { /** @hide User operation call: given user id is the current user, can't be stopped. */ public static final int USER_OP_IS_CURRENT = -2; + /** @hide Process does not exist. */ + public static final int PROCESS_STATE_NONEXISTENT = -1; + /** @hide Process is a persistent system process. */ public static final int PROCESS_STATE_PERSISTENT = 0; diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 452603a7dca4..4723c0db621c 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -644,6 +644,7 @@ public class ActivityInfo extends ComponentInfo /** * Value indicating if the activity is resizeable to any dimension. * See {@link android.R.attr#resizeableActivity}. + * @hide */ public boolean resizeable; diff --git a/core/java/android/hardware/camera2/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java index 6fc99ac1b9f6..33d539c25e73 100644 --- a/core/java/android/hardware/camera2/DngCreator.java +++ b/core/java/android/hardware/camera2/DngCreator.java @@ -530,9 +530,9 @@ public final class DngCreator implements AutoCloseable { int uPixStride = uPlane.getPixelStride(); byte[] yuvPixel = { 0, 0, 0 }; - byte[] yFullRow = new byte[yPixStride * width]; - byte[] uFullRow = new byte[uPixStride * width / 2]; - byte[] vFullRow = new byte[vPixStride * width / 2]; + byte[] yFullRow = new byte[yPixStride * (width - 1) + 1]; + byte[] uFullRow = new byte[uPixStride * (width / 2 - 1) + 1]; + byte[] vFullRow = new byte[vPixStride * (width / 2 - 1) + 1]; byte[] finalRow = new byte[BYTES_PER_RGB_PIX * width]; for (int i = 0; i < height; i++) { int halfH = i / 2; diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java index 2099c3f9b02f..bf3d9aac1da1 100644 --- a/core/java/android/net/Uri.java +++ b/core/java/android/net/Uri.java @@ -366,6 +366,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { public String toSafeString() { String scheme = getScheme(); String ssp = getSchemeSpecificPart(); + String authority = null; if (scheme != null) { if (scheme.equalsIgnoreCase("tel") || scheme.equalsIgnoreCase("sip") || scheme.equalsIgnoreCase("sms") || scheme.equalsIgnoreCase("smsto") @@ -384,6 +385,9 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { } } return builder.toString(); + } else if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) { + ssp = null; + authority = "//" + getAuthority() + "/..."; } } // Not a sensitive scheme, but let's still be conservative about @@ -397,6 +401,9 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { if (ssp != null) { builder.append(ssp); } + if (authority != null) { + builder.append(authority); + } return builder.toString(); } @@ -1742,7 +1749,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return normalized Uri (never null) * @see {@link android.content.Intent#setData} - * @see {@link #setNormalizedData} + * @see {@link android.content.Intent#setDataAndNormalize} */ public Uri normalizeScheme() { String scheme = getScheme(); diff --git a/core/java/android/os/IProcessInfoService.aidl b/core/java/android/os/IProcessInfoService.aidl new file mode 100644 index 000000000000..c98daa282ec4 --- /dev/null +++ b/core/java/android/os/IProcessInfoService.aidl @@ -0,0 +1,29 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +/** {@hide} */ +interface IProcessInfoService +{ + /** + * For each PID in the given input array, write the current process state + * for that process into the output array, or ActivityManager.PROCESS_STATE_NONEXISTENT + * to indicate that no process with the given PID exists. + */ + void getProcessStatesFromPids(in int[] pids, out int[] states); +} + diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 559d750e4340..d157cdc0a055 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -5078,14 +5078,31 @@ <!-- Describes an item (or child) of a LayerDrawable. --> <declare-styleable name="LayerDrawableItem"> - <!-- Left coordinate of the layer. --> + <!-- Left inset to apply to the layer. --> <attr name="left" /> - <!-- Top coordinate of the layer. --> + <!-- Top inset to apply to the layer. --> <attr name="top" /> - <!-- Right coordinate of the layer. --> + <!-- Right inset to apply to the layer. --> <attr name="right" /> - <!-- Bottom coordinate of the layer. --> + <!-- Bottom inset to apply to the layer. --> <attr name="bottom" /> + <!-- Start inset to apply to the layer. Overrides {@code left} or + {@code right} depending on layout direction. --> + <attr name="start" format="dimension" /> + <!-- End inset to apply to the layer. Overrides {@code left} or + {@code right} depending on layout direction. --> + <attr name="end" format="dimension" /> + <!-- Width of the layer. Defaults to the layer's intrinsic width. --> + <attr name="width" /> + <!-- Height of the layer. Defaults to the layer's intrinsic height --> + <attr name="height" /> + <!-- Gravity used to align the layer within its container. If no value + is specified, the default behavior depends on whether an explicit + width or height has been set, If no dimension is set, gravity in + that direction defaults to {@code fill_horizontal} or + {@code fill_vertical}; otherwise, it defaults to {@code left} or + {@code top}. --> + <attr name="gravity" /> <!-- Drawable used to render the layer. --> <attr name="drawable" /> <!-- Identifier of the layer. This can be used to retrieve the layer diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index b9ed78ac4d04..84609cadaf14 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1017,7 +1017,7 @@ at the same time. <p>The default value is <code>false</code> for applications with - <code>targetSdkVersion</code> lesser than {@link android.os.Build.VERSION_CODE#MNC} and + <code>targetSdkVersion</code> lesser than {@link android.os.Build.VERSION_CODES#MNC} and <code>true</code> otherwise. <p>NOTE: A task's root activity value is applied to all additional activities launched in diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 11cc18120074..3bf96318a019 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2611,6 +2611,8 @@ <public type="attr" name="trackTint" /> <public type="attr" name="trackTintMode" /> <public type="attr" name="resizeableActivity" /> + <public type="attr" name="start" /> + <public type="attr" name="end" /> <public type="style" name="Widget.Material.Button.Colored" /> diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index daf44271ef74..505bd1dacaf2 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -29,6 +29,8 @@ import android.graphics.PixelFormat; import android.graphics.PorterDuff.Mode; import android.graphics.Rect; import android.util.AttributeSet; +import android.util.LayoutDirection; +import android.view.Gravity; import android.view.View; import com.android.internal.R; @@ -54,6 +56,11 @@ import java.util.Collection; * @attr ref android.R.styleable#LayerDrawableItem_top * @attr ref android.R.styleable#LayerDrawableItem_right * @attr ref android.R.styleable#LayerDrawableItem_bottom + * @attr ref android.R.styleable#LayerDrawableItem_start + * @attr ref android.R.styleable#LayerDrawableItem_end + * @attr ref android.R.styleable#LayerDrawableItem_width + * @attr ref android.R.styleable#LayerDrawableItem_height + * @attr ref android.R.styleable#LayerDrawableItem_gravity * @attr ref android.R.styleable#LayerDrawableItem_drawable * @attr ref android.R.styleable#LayerDrawableItem_id */ @@ -73,6 +80,9 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { */ public static final int PADDING_MODE_STACK = 1; + /** Value used for undefined start and end insets. */ + private static final int UNDEFINED_INSET = Integer.MIN_VALUE; + LayerState mLayerState; private int mOpacityOverride = PixelFormat.UNKNOWN; @@ -231,6 +241,16 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { R.styleable.LayerDrawableItem_right, layer.mInsetR); layer.mInsetB = a.getDimensionPixelOffset( R.styleable.LayerDrawableItem_bottom, layer.mInsetB); + layer.mInsetS = a.getDimensionPixelOffset( + R.styleable.LayerDrawableItem_start, layer.mInsetS); + layer.mInsetE = a.getDimensionPixelOffset( + R.styleable.LayerDrawableItem_end, layer.mInsetE); + layer.mWidth = a.getDimensionPixelSize( + R.styleable.LayerDrawableItem_width, layer.mWidth); + layer.mHeight = a.getDimensionPixelSize( + R.styleable.LayerDrawableItem_height, layer.mHeight); + layer.mGravity = a.getInteger( + R.styleable.LayerDrawableItem_gravity, layer.mGravity); layer.mId = a.getResourceId(R.styleable.LayerDrawableItem_id, layer.mId); final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable); @@ -447,6 +467,89 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } /** + * Sets an explicit size for the specified layer. + * <p> + * <strong>Note:</strong> Setting an explicit layer size changes the + * default layer gravity behavior. See {@link #setLayerGravity(int, int)} + * for more information. + * + * @param index the index of the drawable to adjust + * @param w width in pixels, or -1 to use the intrinsic width + * @param h height in pixels, or -1 to use the intrinsic height + * + * @see #getLayerWidth(int) + * @see #getLayerHeight(int) + * @attr ref android.R.styleable#LayerDrawableItem_width + * @attr ref android.R.styleable#LayerDrawableItem_height + */ + public void setLayerSize(int index, int w, int h) { + final ChildDrawable childDrawable = mLayerState.mChildren[index]; + childDrawable.mWidth = w; + childDrawable.mHeight = h; + } + + /** + * @param index the index of the drawable to adjust + * @return the explicit width of the layer, or -1 if not specified + * + * @see #setLayerSize(int, int, int) + * @attr ref android.R.styleable#LayerDrawableItem_width + */ + public int getLayerWidth(int index) { + final ChildDrawable childDrawable = mLayerState.mChildren[index]; + return childDrawable.mWidth; + } + + /** + * @param index the index of the drawable to adjust + * @return the explicit height of the layer, or -1 if not specified + * + * @see #setLayerSize(int, int, int) + * @attr ref android.R.styleable#LayerDrawableItem_height + */ + public int getLayerHeight(int index) { + final ChildDrawable childDrawable = mLayerState.mChildren[index]; + return childDrawable.mHeight; + } + + /** + * Sets the gravity used to position or stretch the specified layer within + * its container. Gravity is applied after any layer insets (see + * {@link #setLayerInset(int, int, int, int, int)}) or padding (see + * {@link #setPaddingMode(int)}). + * <p> + * If gravity is specified as {@link Gravity#NO_GRAVITY}, the default + * behavior depends on whether an explicit width or height has been set + * (see {@link #setLayerSize(int, int, int)}), If a dimension is not set, + * gravity in that direction defaults to {@link Gravity#FILL_HORIZONTAL} or + * {@link Gravity#FILL_VERTICAL}; otherwise, gravity in that direction + * defaults to {@link Gravity#LEFT} or {@link Gravity#TOP}. + * + * @param index the index of the drawable to adjust + * @param gravity the gravity to set for the layer + * + * @see #getLayerGravity(int) + * @attr ref android.R.styleable#LayerDrawableItem_gravity + */ + public void setLayerGravity(int index, int gravity) { + final ChildDrawable childDrawable = mLayerState.mChildren[index]; + childDrawable.mGravity = gravity; + } + + /** + * @param index the index of the layer + * @return the gravity used to position or stretch the specified layer + * within its container + * + * @see #setLayerGravity(int, int) + * @attr ref android.R.styleable#LayerDrawableItem_gravity + */ + public int getLayerGravity(int index) { + final ChildDrawable childDrawable = mLayerState.mChildren[index]; + return childDrawable.mGravity; + } + + /** * Specifies the insets in pixels for the drawable at the specified index. * * @param index the index of the drawable to adjust @@ -454,13 +557,43 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * @param t number of pixels to add to the top bound * @param r number of pixels to subtract from the right bound * @param b number of pixels to subtract from the bottom bound + * + * @attr ref android.R.styleable#LayerDrawableItem_left + * @attr ref android.R.styleable#LayerDrawableItem_top + * @attr ref android.R.styleable#LayerDrawableItem_right + * @attr ref android.R.styleable#LayerDrawableItem_bottom */ public void setLayerInset(int index, int l, int t, int r, int b) { + setLayerInsetInternal(index, l, t, r, b, UNDEFINED_INSET, UNDEFINED_INSET); + } + + /** + * Specifies the relative insets in pixels for the drawable at the + * specified index. + * + * @param index the index of the drawable to adjust + * @param s number of pixels to inset from the start bound + * @param t number of pixels to inset from the top bound + * @param e number of pixels to inset from the end bound + * @param b number of pixels to inset from the bottom bound + * + * @attr ref android.R.styleable#LayerDrawableItem_start + * @attr ref android.R.styleable#LayerDrawableItem_top + * @attr ref android.R.styleable#LayerDrawableItem_end + * @attr ref android.R.styleable#LayerDrawableItem_bottom + */ + public void setLayerInsetRelative(int index, int s, int t, int e, int b) { + setLayerInsetInternal(index, 0, t, 0, b, s, e); + } + + private void setLayerInsetInternal(int index, int l, int t, int r, int b, int s, int e) { final ChildDrawable childDrawable = mLayerState.mChildren[index]; childDrawable.mInsetL = l; childDrawable.mInsetT = t; childDrawable.mInsetR = r; childDrawable.mInsetB = b; + childDrawable.mInsetS = s; + childDrawable.mInsetE = e; } /** @@ -770,7 +903,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } if (paddingChanged) { - onBoundsChange(getBounds()); + updateLayerBounds(getBounds()); } return changed; @@ -795,7 +928,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } if (paddingChanged) { - onBoundsChange(getBounds()); + updateLayerBounds(getBounds()); } return changed; @@ -803,18 +936,50 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override protected void onBoundsChange(Rect bounds) { + updateLayerBounds(bounds); + } + + private void updateLayerBounds(Rect bounds) { int padL = 0; int padT = 0; int padR = 0; int padB = 0; + final Rect outRect = mTmpRect; + final int layoutDirection = getLayoutDirection(); final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; - r.mDrawable.setBounds(bounds.left + r.mInsetL + padL, bounds.top + r.mInsetT + padT, - bounds.right - r.mInsetR - padR, bounds.bottom - r.mInsetB - padB); + final Drawable d = r.mDrawable; + final Rect container = d.getBounds(); + + // Take the resolved layout direction into account. If start / end + // padding are defined, they will be resolved (hence overriding) to + // left / right or right / left depending on the resolved layout + // direction. If start / end padding are not defined, use the + // left / right ones. + final int insetL, insetR; + if (layoutDirection == LayoutDirection.RTL) { + insetL = r.mInsetE == UNDEFINED_INSET ? r.mInsetL : r.mInsetE; + insetR = r.mInsetS == UNDEFINED_INSET ? r.mInsetR : r.mInsetS; + } else { + insetL = r.mInsetS == UNDEFINED_INSET ? r.mInsetL : r.mInsetS; + insetR = r.mInsetE == UNDEFINED_INSET ? r.mInsetR : r.mInsetE; + } + + // Establish containing region based on aggregate padding and + // requested insets for the current layer. + container.set(bounds.left + insetL + padL, bounds.top + r.mInsetT + padT, + bounds.right - insetR - padR, bounds.bottom - r.mInsetB - padB); + + // Apply resolved gravity to drawable based on resolved size. + final int gravity = resolveGravity(r.mGravity, r.mWidth, r.mHeight); + final int w = r.mWidth < 0 ? d.getIntrinsicWidth() : r.mWidth; + final int h = r.mHeight < 0 ? d.getIntrinsicHeight() : r.mHeight; + Gravity.apply(gravity, w, h, container, outRect, layoutDirection); + d.setBounds(outRect); if (nest) { padL += mPaddingL[i]; @@ -825,6 +990,38 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } + /** + * Resolves layer gravity given explicit gravity and dimensions. + * <p> + * If the client hasn't specified a gravity but has specified an explicit + * dimension, defaults to START or TOP. Otherwise, defaults to FILL to + * preserve legacy behavior. + * + * @param gravity + * @param width + * @param height + * @return + */ + private int resolveGravity(int gravity, int width, int height) { + if (!Gravity.isHorizontal(gravity)) { + if (width < 0) { + gravity |= Gravity.FILL_HORIZONTAL; + } else { + gravity |= Gravity.START; + } + } + + if (!Gravity.isVertical(gravity)) { + if (height < 0) { + gravity |= Gravity.FILL_VERTICAL; + } else { + gravity |= Gravity.TOP; + } + } + + return gravity; + } + @Override public int getIntrinsicWidth() { int width = -1; @@ -836,7 +1033,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; - final int w = r.mDrawable.getIntrinsicWidth() + r.mInsetL + r.mInsetR + padL + padR; + final int minWidth = r.mWidth < 0 ? r.mDrawable.getIntrinsicWidth() : r.mWidth; + final int w = minWidth + r.mInsetL + r.mInsetR + padL + padR; if (w > width) { width = w; } @@ -861,7 +1059,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; - int h = r.mDrawable.getIntrinsicHeight() + r.mInsetT + r.mInsetB + padT + padB; + final int minHeight = r.mHeight < 0 ? r.mDrawable.getIntrinsicHeight() : r.mHeight; + final int h = minHeight + r.mInsetT + r.mInsetB + padT + padB; if (h > height) { height = h; } @@ -948,18 +1147,24 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { /** @hide */ @Override public void setLayoutDirection(int layoutDirection) { + super.setLayoutDirection(layoutDirection); final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { array[i].mDrawable.setLayoutDirection(layoutDirection); } - super.setLayoutDirection(layoutDirection); + updateLayerBounds(getBounds()); } static class ChildDrawable { public Drawable mDrawable; public int[] mThemeAttrs; public int mInsetL, mInsetT, mInsetR, mInsetB; + public int mInsetS = UNDEFINED_INSET; + public int mInsetE = UNDEFINED_INSET; + public int mWidth = -1; + public int mHeight = -1; + public int mGravity = Gravity.NO_GRAVITY; public int mId = View.NO_ID; ChildDrawable() { @@ -981,6 +1186,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mInsetT = orig.mInsetT; mInsetR = orig.mInsetR; mInsetB = orig.mInsetB; + mInsetS = orig.mInsetS; + mInsetE = orig.mInsetE; + mWidth = orig.mWidth; + mHeight = orig.mHeight; + mGravity = orig.mGravity; mId = orig.mId; } } diff --git a/location/java/android/location/GpsSatellite.java b/location/java/android/location/GpsSatellite.java index 17af4a647461..820f574653a9 100644 --- a/location/java/android/location/GpsSatellite.java +++ b/location/java/android/location/GpsSatellite.java @@ -40,13 +40,17 @@ public final class GpsSatellite { * cached GpsStatus instance to the client's copy. */ void setStatus(GpsSatellite satellite) { - mValid = satellite.mValid; - mHasEphemeris = satellite.mHasEphemeris; - mHasAlmanac = satellite.mHasAlmanac; - mUsedInFix = satellite.mUsedInFix; - mSnr = satellite.mSnr; - mElevation = satellite.mElevation; - mAzimuth = satellite.mAzimuth; + if (satellite == null) { + mValid = false; + } else { + mValid = satellite.mValid; + mHasEphemeris = satellite.mHasEphemeris; + mHasAlmanac = satellite.mHasAlmanac; + mUsedInFix = satellite.mUsedInFix; + mSnr = satellite.mSnr; + mElevation = satellite.mElevation; + mAzimuth = satellite.mAzimuth; + } } /** diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java index 4af55a65b0e3..323f3269368e 100644 --- a/location/java/android/location/GpsStatus.java +++ b/location/java/android/location/GpsStatus.java @@ -16,6 +16,8 @@ package android.location; +import android.util.SparseArray; + import java.util.Iterator; import java.util.NoSuchElementException; @@ -29,20 +31,24 @@ public final class GpsStatus { /* These package private values are modified by the LocationManager class */ private int mTimeToFirstFix; - private GpsSatellite mSatellites[] = new GpsSatellite[NUM_SATELLITES]; + private final SparseArray<GpsSatellite> mSatellites = new SparseArray<>(); private final class SatelliteIterator implements Iterator<GpsSatellite> { - private GpsSatellite[] mSatellites; - int mIndex = 0; + private final SparseArray<GpsSatellite> mSatellites; + private final int mSatellitesCount; + + private int mIndex = 0; - SatelliteIterator(GpsSatellite[] satellites) { + SatelliteIterator(SparseArray<GpsSatellite> satellites) { mSatellites = satellites; + mSatellitesCount = satellites.size(); } public boolean hasNext() { - for (int i = mIndex; i < mSatellites.length; i++) { - if (mSatellites[i].mValid) { + for (; mIndex < mSatellitesCount; ++mIndex) { + GpsSatellite satellite = mSatellites.valueAt(mIndex); + if (satellite.mValid) { return true; } } @@ -50,8 +56,9 @@ public final class GpsStatus { } public GpsSatellite next() { - while (mIndex < mSatellites.length) { - GpsSatellite satellite = mSatellites[mIndex++]; + while (mIndex < mSatellitesCount) { + GpsSatellite satellite = mSatellites.valueAt(mIndex); + ++mIndex; if (satellite.mValid) { return satellite; } @@ -106,7 +113,7 @@ public final class GpsStatus { * <li> {@link GpsStatus#GPS_EVENT_SATELLITE_STATUS} * </ul> * - * When this method is called, the client should call + * When this method is called, the client should call * {@link LocationManager#getGpsStatus} to get additional * status information. * @@ -127,11 +134,8 @@ public final class GpsStatus { void onNmeaReceived(long timestamp, String nmea); } - GpsStatus() { - for (int i = 0; i < mSatellites.length; i++) { - mSatellites[i] = new GpsSatellite(i + 1); - } - } + // For API-compat a public ctor() is not available + GpsStatus() {} /** * Used internally within {@link LocationManager} to copy GPS status @@ -141,18 +145,17 @@ public final class GpsStatus { synchronized void setStatus(int svCount, int[] prns, float[] snrs, float[] elevations, float[] azimuths, int ephemerisMask, int almanacMask, int usedInFixMask) { - int i; + clearSatellites(); + for (int i = 0; i < svCount; i++) { + int prn = prns[i]; + int prnShift = (1 << (prn - 1)); + if (prn > 0 && prn <= NUM_SATELLITES) { + GpsSatellite satellite = mSatellites.get(prn); + if (satellite == null) { + satellite = new GpsSatellite(prn); + mSatellites.put(prn, satellite); + } - for (i = 0; i < mSatellites.length; i++) { - mSatellites[i].mValid = false; - } - - for (i = 0; i < svCount; i++) { - int prn = prns[i] - 1; - int prnShift = (1 << prn); - if (prn >= 0 && prn < mSatellites.length) { - GpsSatellite satellite = mSatellites[prn]; - satellite.mValid = true; satellite.mSnr = snrs[i]; satellite.mElevation = elevations[i]; @@ -172,10 +175,38 @@ public final class GpsStatus { */ void setStatus(GpsStatus status) { mTimeToFirstFix = status.getTimeToFirstFix(); + clearSatellites(); + + SparseArray<GpsSatellite> otherSatellites = status.mSatellites; + int otherSatellitesCount = otherSatellites.size(); + int satelliteIndex = 0; + // merge both sparse arrays, note that we have already invalidated the elements in the + // receiver array + for (int i = 0; i < otherSatellitesCount; ++i) { + GpsSatellite otherSatellite = otherSatellites.valueAt(i); + int otherSatellitePrn = otherSatellite.getPrn(); + + int satellitesCount = mSatellites.size(); + while (satelliteIndex < satellitesCount + && mSatellites.valueAt(satelliteIndex).getPrn() < otherSatellitePrn) { + ++satelliteIndex; + } - for (int i = 0; i < mSatellites.length; i++) { - mSatellites[i].setStatus(status.mSatellites[i]); - } + if (satelliteIndex < mSatellites.size()) { + GpsSatellite satellite = mSatellites.valueAt(satelliteIndex); + if (satellite.getPrn() == otherSatellitePrn) { + satellite.setStatus(otherSatellite); + } else { + satellite = new GpsSatellite(otherSatellitePrn); + satellite.setStatus(otherSatellite); + mSatellites.put(otherSatellitePrn, satellite); + } + } else { + GpsSatellite satellite = new GpsSatellite(otherSatellitePrn); + satellite.setStatus(otherSatellite); + mSatellites.append(otherSatellitePrn, satellite); + } + } } void setTimeToFirstFix(int ttff) { @@ -183,7 +214,7 @@ public final class GpsStatus { } /** - * Returns the time required to receive the first fix since the most recent + * Returns the time required to receive the first fix since the most recent * restart of the GPS engine. * * @return time to first fix in milliseconds @@ -211,4 +242,12 @@ public final class GpsStatus { public int getMaxSatellites() { return NUM_SATELLITES; } + + private void clearSatellites() { + int satellitesCount = mSatellites.size(); + for (int i = 0; i < satellitesCount; i++) { + GpsSatellite satellite = mSatellites.valueAt(i); + satellite.mValid = false; + } + } } diff --git a/location/tests/locationtests/src/android/location/GpsStatusTest.java b/location/tests/locationtests/src/android/location/GpsStatusTest.java new file mode 100644 index 000000000000..4808fafa272e --- /dev/null +++ b/location/tests/locationtests/src/android/location/GpsStatusTest.java @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package android.location; + +import junit.framework.TestCase; + +import android.test.suitebuilder.annotation.SmallTest; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Random; +import java.util.Set; + +/** + * Unit tests for {@link GpsStatus}. + */ +@SmallTest +public class GpsStatusTest extends TestCase { + + private static final int MAX_VALUE = 250; + + private final Random mRandom = new Random(); + + private GpsStatus mStatus; + private int mCount; + private int[] mPrns; + private float[] mSnrs; + private float[] mElevations; + private float[] mAzimuth; + private int mEphemerisMask; + private int mAlmanacMask; + private int mUsedInFixMask; + + public void setUp() throws Exception { + super.setUp(); + mStatus = createGpsStatus(); + generateSatellitesData(generateInt()); + } + + public void testEmptyGpsStatus() throws Exception { + verifyIsEmpty(mStatus); + } + + public void testGpsStatusIterator() throws Exception { + generateSatellitesData(2); + setSatellites(mStatus); + Iterator<GpsSatellite> iterator = mStatus.getSatellites().iterator(); + assertTrue("hasNext(1)", iterator.hasNext()); + assertTrue("hasNext(1) does not overflow", iterator.hasNext()); + GpsSatellite satellite1 = iterator.next(); + assertNotNull("satellite", satellite1); + assertTrue("hasNext(2)", iterator.hasNext()); + assertTrue("hasNext(2) does not overflow", iterator.hasNext()); + GpsSatellite satellite2 = iterator.next(); + assertNotNull("satellite", satellite2); + assertFalse("hasNext() no elements", iterator.hasNext()); + } + + public void testTtff() throws Exception { + int testTtff = generateInt(); + set(mStatus, testTtff); + verifyTtff(mStatus, testTtff); + } + + public void testCopyTtff() throws Exception { + int testTtff = generateInt(); + verifyTtff(mStatus, 0); + + GpsStatus otherStatus = createGpsStatus(); + set(otherStatus, testTtff); + verifyTtff(otherStatus, testTtff); + + set(mStatus, otherStatus); + verifyTtff(mStatus, testTtff); + } + + public void testSetSatellites() throws Exception { + setSatellites(mStatus); + verifySatellites(mStatus); + } + + public void testCopySatellites() throws Exception { + verifyIsEmpty(mStatus); + + GpsStatus otherStatus = createGpsStatus(); + setSatellites(otherStatus); + verifySatellites(otherStatus); + + set(mStatus, otherStatus); + verifySatellites(mStatus); + } + + public void testOverrideSatellites() throws Exception { + setSatellites(mStatus); + verifySatellites(mStatus); + + GpsStatus otherStatus = createGpsStatus(); + generateSatellitesData(mCount, true /* reusePrns */); + setSatellites(otherStatus); + verifySatellites(otherStatus); + + set(mStatus, otherStatus); + verifySatellites(mStatus); + } + + public void testAddSatellites() throws Exception { + int count = 10; + generateSatellitesData(count); + setSatellites(mStatus); + verifySatellites(mStatus); + + GpsStatus otherStatus = createGpsStatus(); + generateSatellitesData(count); + setSatellites(otherStatus); + verifySatellites(otherStatus); + + set(mStatus, otherStatus); + verifySatellites(mStatus); + } + + public void testAddMoreSatellites() throws Exception { + int count = 25; + generateSatellitesData(count); + setSatellites(mStatus); + verifySatellites(mStatus); + + GpsStatus otherStatus = createGpsStatus(); + generateSatellitesData(count * 2); + setSatellites(otherStatus); + verifySatellites(otherStatus); + + set(mStatus, otherStatus); + verifySatellites(mStatus); + } + + public void testAddLessSatellites() throws Exception { + int count = 25; + generateSatellitesData(count * 2); + setSatellites(mStatus); + verifySatellites(mStatus); + + GpsStatus otherStatus = createGpsStatus(); + generateSatellitesData(count); + setSatellites(otherStatus); + verifySatellites(otherStatus); + + set(mStatus, otherStatus); + verifySatellites(mStatus); + } + + private static void verifyIsEmpty(GpsStatus status) { + verifySatelliteCount(status, 0); + verifyTtff(status, 0); + } + + private static void verifySatelliteCount(GpsStatus status, int expectedCount) { + int satellites = 0; + for (GpsSatellite s : status.getSatellites()) { + ++satellites; + } + assertEquals("GpsStatus::SatelliteCount", expectedCount, satellites); + } + + private void verifySatellites(GpsStatus status) { + verifySatelliteCount(status, mCount); + verifySatellites(status, mCount, mPrns, mSnrs, mElevations, mAzimuth, mEphemerisMask, + mAlmanacMask, mUsedInFixMask); + } + + private static void verifySatellites( + GpsStatus status, + int count, + int[] prns, + float[] snrs, + float[] elevations, + float[] azimuth, + int ephemerisMask, + int almanacMask, + int usedInFixMask) { + for (int i = 0; i < count; ++i) { + int prn = prns[i]; + GpsSatellite satellite = getSatellite(status, prn); + assertNotNull(getSatelliteAssertInfo(i, prn, "non-null"), satellite); + assertEquals(getSatelliteAssertInfo(i, prn, "Snr"), snrs[i], satellite.getSnr()); + assertEquals( + getSatelliteAssertInfo(i, prn, "Elevation"), + elevations[i], + satellite.getElevation()); + assertEquals( + getSatelliteAssertInfo(i, prn, "Azimuth"), + azimuth[i], + satellite.getAzimuth()); + int prnShift = 1 << (prn - 1); + assertEquals( + getSatelliteAssertInfo(i, prn, "ephemeris"), + (ephemerisMask & prnShift) != 0, + satellite.hasEphemeris()); + assertEquals( + getSatelliteAssertInfo(i, prn, "almanac"), + (almanacMask & prnShift) != 0, + satellite.hasAlmanac()); + assertEquals( + getSatelliteAssertInfo(i, prn, "usedInFix"), + (usedInFixMask & prnShift) != 0, + satellite.usedInFix()); + } + } + + private static void verifyTtff(GpsStatus status, int expectedTtff) { + assertEquals("GpsStatus::TTFF", expectedTtff, status.getTimeToFirstFix()); + } + + private static GpsStatus createGpsStatus() throws Exception { + Constructor<GpsStatus> ctor = GpsStatus.class.getDeclaredConstructor(); + ctor.setAccessible(true); + return ctor.newInstance(); + } + + private static void set(GpsStatus status, int ttff) throws Exception { + Class<?> statusClass = status.getClass(); + Method setTtff = statusClass.getDeclaredMethod("setTimeToFirstFix", Integer.TYPE); + setTtff.setAccessible(true); + setTtff.invoke(status, ttff); + } + + private static void set(GpsStatus status, GpsStatus statusToSet) throws Exception { + Class<?> statusClass = status.getClass(); + Method setStatus = statusClass.getDeclaredMethod("setStatus", statusClass); + setStatus.setAccessible(true); + setStatus.invoke(status, statusToSet); + } + + private void setSatellites(GpsStatus status) throws Exception { + set(status, mCount, mPrns, mSnrs, mElevations, mAzimuth, mEphemerisMask, mAlmanacMask, + mUsedInFixMask); + } + + private static void set( + GpsStatus status, + int count, + int[] prns, + float[] snrs, + float[] elevations, + float[] azimuth, + int ephemerisMask, + int almanacMask, + int usedInFixMask) throws Exception { + Class<?> statusClass = status.getClass(); + Class<?> intClass = Integer.TYPE; + Class<?> floatArrayClass = Class.forName("[F"); + Method setStatus = statusClass.getDeclaredMethod( + "setStatus", + intClass, + Class.forName("[I"), + floatArrayClass, + floatArrayClass, + floatArrayClass, + intClass, + intClass, + intClass); + setStatus.setAccessible(true); + setStatus.invoke( + status, + count, + prns, + snrs, + elevations, + azimuth, + ephemerisMask, + almanacMask, + usedInFixMask); + } + + private int generateInt() { + return mRandom.nextInt(MAX_VALUE) + 1; + } + + private int[] generateIntArray(int count) { + Set<Integer> generatedPrns = new HashSet<>(); + int[] array = new int[count]; + for(int i = 0; i < count; ++i) { + int generated; + do { + generated = generateInt(); + } while (generatedPrns.contains(generated)); + array[i] = generated; + generatedPrns.add(generated); + } + return array; + } + + private float[] generateFloatArray(int count) { + float[] array = new float[count]; + for(int i = 0; i < count; ++i) { + array[i] = generateInt(); + } + return array; + } + + private int generateMask(int[] prns) { + int mask = 0; + int prnsLength = prns.length; + for (int i = 0; i < prnsLength; ++i) { + if (mRandom.nextBoolean()) { + mask |= 1 << (prns[i] - 1); + } + } + return mask; + } + + private void generateSatellitesData(int count) { + generateSatellitesData(count, false /* reusePrns */); + } + + private void generateSatellitesData(int count, boolean reusePrns) { + mCount = count; + if (!reusePrns) { + mPrns = generateIntArray(count); + } + mSnrs = generateFloatArray(count); + mElevations = generateFloatArray(count); + mAzimuth = generateFloatArray(count); + mEphemerisMask = generateMask(mPrns); + mAlmanacMask = generateMask(mPrns); + mUsedInFixMask = generateMask(mPrns); + } + + private static GpsSatellite getSatellite(GpsStatus status, int prn) { + for (GpsSatellite satellite : status.getSatellites()) { + if (satellite.getPrn() == prn) { + return satellite; + } + } + return null; + } + + private static String getSatelliteAssertInfo(int index, int prn, String param) { + return String.format("Satellite::%s [i=%d, prn=%d]", param, index, prn); + } +} diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 489f5524d934..ca242e4bcbe0 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -709,7 +709,13 @@ public final class AudioAttributes implements Parcelable { } } - /** @hide */ + /** + * @hide + * Only use to get which stream type should be used for volume control, NOT for audio playback + * (all audio playback APIs are supposed to take AudioAttributes as input parameters) + * @param aa non-null AudioAttributes. + * @return a valid stream type for volume control that matches the attributes. + */ public static int toLegacyStreamType(AudioAttributes aa) { // flags to stream type mapping if ((aa.getFlags() & FLAG_AUDIBILITY_ENFORCED) == FLAG_AUDIBILITY_ENFORCED) { diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java index 5b922664e15e..bc9722e264b4 100644 --- a/media/java/android/media/tv/TvContract.java +++ b/media/java/android/media/tv/TvContract.java @@ -756,8 +756,9 @@ public final class TvContract { * </p><p> * Note that this sub-directory also supports opening the logo as an asset file in write * mode. Callers can create or replace the primary logo associated with this channel by - * opening the asset file and writing the full-size photo contents into it. When the file - * is closed, the image will be parsed, sized down if necessary, and stored. + * opening the asset file and writing the full-size photo contents into it. (Make sure there + * is no padding around the logo image.) When the file is closed, the image will be parsed, + * sized down if necessary, and stored. * </p><p> * Usage example: * <pre> diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index 1bed55345de9..ea4c4baa547d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -74,7 +74,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV RecentsViewLayoutAlgorithm mLayoutAlgorithm; ArrayList<TaskStack> mStacks; - List<TaskStackView> mImmutableTaskStackViews = new ArrayList<TaskStackView>(); + List<TaskStackView> mTaskStackViews = new ArrayList<>(); View mSearchBar; RecentsViewCallbacks mCb; @@ -133,24 +133,18 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV public void setTaskStacks(ArrayList<TaskStack> stacks) { int numStacks = stacks.size(); - // Make a list of the stack view children only - ArrayList<TaskStackView> stackViewsList = new ArrayList<TaskStackView>(); - List<TaskStackView> stackViews = getTaskStackViews(); - // Remove all/extra stack views int numTaskStacksToKeep = 0; // Keep no tasks if we are recreating the layout if (mConfig.launchedReuseTaskStackViews) { - numTaskStacksToKeep = Math.min(stackViews.size(), numStacks); + numTaskStacksToKeep = Math.min(mTaskStackViews.size(), numStacks); } - for (int i = stackViews.size() - 1; i >= numTaskStacksToKeep; i--) { - removeView(stackViews.get(i)); - stackViews.remove(i); + for (int i = mTaskStackViews.size() - 1; i >= numTaskStacksToKeep; i--) { + removeView(mTaskStackViews.remove(i)); } - stackViewsList.addAll(stackViews); // Update the stack views that we are keeping for (int i = 0; i < numTaskStacksToKeep; i++) { - TaskStackView tsv = stackViews.get(i); + TaskStackView tsv = mTaskStackViews.get(i); // If onRecentsHidden is not triggered, we need to the stack view again here tsv.reset(); tsv.setStack(stacks.get(i)); @@ -158,21 +152,18 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // Add remaining/recreate stack views mStacks = stacks; - for (int i = stackViews.size(); i < numStacks; i++) { + for (int i = mTaskStackViews.size(); i < numStacks; i++) { TaskStack stack = stacks.get(i); TaskStackView stackView = new TaskStackView(getContext(), stack); stackView.setCallbacks(this); addView(stackView); - stackViewsList.add(stackView); + mTaskStackViews.add(stackView); } - // Set the immutable stack views list - mImmutableTaskStackViews = Collections.unmodifiableList(stackViewsList); - // Enable debug mode drawing on all the stacks if necessary if (mConfig.debugModeEnabled) { - for (int i = mImmutableTaskStackViews.size() - 1; i >= 0; i--) { - TaskStackView stackView = mImmutableTaskStackViews.get(i); + for (int i = mTaskStackViews.size() - 1; i >= 0; i--) { + TaskStackView stackView = mTaskStackViews.get(i); stackView.setDebugOverlay(mDebugOverlay); } } @@ -188,7 +179,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV /** Gets the list of task views */ List<TaskStackView> getTaskStackViews() { - return mImmutableTaskStackViews; + return mTaskStackViews; } /** Launches the focused task from the first stack if possible */ diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 640f1619ea71..7a493c6d0e3b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -170,6 +170,7 @@ import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; import android.os.IPermissionController; +import android.os.IProcessInfoService; import android.os.IRemoteCallback; import android.os.IUserManager; import android.os.Looper; @@ -1920,6 +1921,7 @@ public final class ActivityManagerService extends ActivityManagerNative ServiceManager.addService("cpuinfo", new CpuBinder(this)); } ServiceManager.addService("permission", new PermissionController(this)); + ServiceManager.addService("processinfo", new ProcessInfoService(this)); ApplicationInfo info = mContext.getPackageManager().getApplicationInfo( "android", STOCK_PM_FLAGS); @@ -6287,7 +6289,46 @@ public final class ActivityManagerService extends ActivityManagerNative } } } - + + // ========================================================= + // PROCESS INFO + // ========================================================= + + static class ProcessInfoService extends IProcessInfoService.Stub { + final ActivityManagerService mActivityManagerService; + ProcessInfoService(ActivityManagerService activityManagerService) { + mActivityManagerService = activityManagerService; + } + + @Override + public void getProcessStatesFromPids(/*in*/ int[] pids, /*out*/ int[] states) { + mActivityManagerService.getProcessStatesForPIDs(/*in*/ pids, /*out*/ states); + } + } + + /** + * For each PID in the given input array, write the current process state + * for that process into the output array, or -1 to indicate that no + * process with the given PID exists. + */ + public void getProcessStatesForPIDs(/*in*/ int[] pids, /*out*/ int[] states) { + if (pids == null) { + throw new NullPointerException("pids"); + } else if (states == null) { + throw new NullPointerException("states"); + } else if (pids.length != states.length) { + throw new IllegalArgumentException("input and output arrays have different lengths!"); + } + + synchronized (mPidsSelfLocked) { + for (int i = 0; i < pids.length; i++) { + ProcessRecord pr = mPidsSelfLocked.get(pids[i]); + states[i] = (pr == null) ? ActivityManager.PROCESS_STATE_NONEXISTENT : + pr.curProcState; + } + } + } + // ========================================================= // PERMISSIONS // ========================================================= diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index f900d0db0308..87f78c1bb448 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -28,6 +28,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkRequest; +import android.net.ProxyInfo; import android.net.TrafficStats; import android.net.Uri; import android.net.wifi.WifiInfo; @@ -656,12 +657,36 @@ public class NetworkMonitor extends StateMachine { int httpResponseCode = 599; try { URL url = new URL("http", mServer, "/generate_204"); + // On networks with a PAC instead of fetching a URL that should result in a 204 + // reponse, we instead simply fetch the PAC script. This is done for a few reasons: + // 1. At present our PAC code does not yet handle multiple PACs on multiple networks + // until something like https://android-review.googlesource.com/#/c/115180/ lands. + // Network.openConnection() will ignore network-specific PACs and instead fetch + // using NO_PROXY. If a PAC is in place, the only fetch we know will succeed with + // NO_PROXY is the fetch of the PAC itself. + // 2. To proxy the generate_204 fetch through a PAC would require a number of things + // happen before the fetch can commence, namely: + // a) the PAC script be fetched + // b) a PAC script resolver service be fired up and resolve mServer + // Network validation could be delayed until these prerequisities are satisifed or + // could simply be left to race them. Neither is an optimal solution. + // 3. PAC scripts are sometimes used to block or restrict Internet access and may in + // fact block fetching of the generate_204 URL which would lead to false negative + // results for network validation. + boolean fetchPac = false; + { + final ProxyInfo proxyInfo = mNetworkAgentInfo.linkProperties.getHttpProxy(); + if (proxyInfo != null && !Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) { + url = new URL(proxyInfo.getPacFileUrl().toString()); + fetchPac = true; + } + } if (DBG) { log("Checking " + url.toString() + " on " + mNetworkAgentInfo.networkInfo.getExtraInfo()); } urlConnection = (HttpURLConnection) mNetworkAgentInfo.network.openConnection(url); - urlConnection.setInstanceFollowRedirects(false); + urlConnection.setInstanceFollowRedirects(fetchPac); urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); urlConnection.setUseCaches(false); @@ -695,6 +720,11 @@ public class NetworkMonitor extends StateMachine { httpResponseCode = 204; } + if (httpResponseCode == 200 && fetchPac) { + if (DBG) log("PAC fetch 200 response interpreted as 204 response."); + httpResponseCode = 204; + } + sendNetworkConditionsBroadcast(true /* response received */, httpResponseCode != 204 /* isCaptivePortal */, requestTimestamp, responseTimestamp); |