summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ApplicationPackageManager.java3
-rw-r--r--core/java/android/net/DhcpResults.java9
-rw-r--r--core/java/android/net/NetworkPolicyManager.java28
-rw-r--r--core/java/android/os/Debug.java10
-rw-r--r--core/java/android/view/SurfaceView.java3
-rw-r--r--core/java/android/view/View.java10
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java273
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java8
-rw-r--r--core/java/com/android/internal/widget/ResolverDrawerLayout.java111
9 files changed, 363 insertions, 92 deletions
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 0adce5d..7cae745 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1619,7 +1619,8 @@ final class ApplicationPackageManager extends PackageManager {
// System apps and apps demanding internal storage can't be moved
// anywhere else
if (app.isSystemApp()
- || app.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
+ || app.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY
+ || app.installLocation == PackageInfo.INSTALL_LOCATION_UNSPECIFIED) {
return false;
}
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index 87c063f..97bd5d2 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -21,7 +21,6 @@ import android.os.Parcel;
import android.text.TextUtils;
import android.util.Log;
-import java.net.InetAddress;
import java.net.Inet4Address;
import java.util.Objects;
@@ -34,7 +33,7 @@ import java.util.Objects;
public class DhcpResults extends StaticIpConfiguration {
private static final String TAG = "DhcpResults";
- public InetAddress serverAddress;
+ public Inet4Address serverAddress;
/** Vendor specific information (from RFC 2132). */
public String vendorInfo;
@@ -142,7 +141,7 @@ public class DhcpResults extends StaticIpConfiguration {
private static void readFromParcel(DhcpResults dhcpResults, Parcel in) {
StaticIpConfiguration.readFromParcel(dhcpResults, in);
dhcpResults.leaseDuration = in.readInt();
- dhcpResults.serverAddress = NetworkUtils.unparcelInetAddress(in);
+ dhcpResults.serverAddress = (Inet4Address) NetworkUtils.unparcelInetAddress(in);
dhcpResults.vendorInfo = in.readString();
}
@@ -183,8 +182,8 @@ public class DhcpResults extends StaticIpConfiguration {
public boolean setServerAddress(String addrString) {
try {
- serverAddress = NetworkUtils.numericToInetAddress(addrString);
- } catch (IllegalArgumentException e) {
+ serverAddress = (Inet4Address) NetworkUtils.numericToInetAddress(addrString);
+ } catch (IllegalArgumentException|ClassCastException e) {
Log.e(TAG, "setServerAddress failed with addrString " + addrString);
return true;
}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 3f40484..a83e722 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -50,12 +50,13 @@ public class NetworkPolicyManager {
public static final int POLICY_ALLOW_BACKGROUND_BATTERY_SAVE = 0x2;
/* RULE_* are not masks and they must be exclusive */
+ public static final int RULE_UNKNOWN = -1;
/** All network traffic should be allowed. */
- public static final int RULE_ALLOW_ALL = 0x0;
+ public static final int RULE_ALLOW_ALL = 0;
/** Reject traffic on metered networks. */
- public static final int RULE_REJECT_METERED = 0x1;
+ public static final int RULE_REJECT_METERED = 1;
/** Reject traffic on all networks. */
- public static final int RULE_REJECT_ALL = 0x2;
+ public static final int RULE_REJECT_ALL = 2;
public static final int FIREWALL_RULE_DEFAULT = 0;
public static final int FIREWALL_RULE_ALLOW = 1;
@@ -326,25 +327,4 @@ public class NetworkPolicyManager {
// nothing found above; we can apply policy to UID
return true;
}
-
- /** {@hide} */
- public static void dumpPolicy(PrintWriter fout, int policy) {
- fout.write("[");
- if ((policy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
- fout.write("REJECT_METERED_BACKGROUND");
- }
- fout.write("]");
- }
-
- /** {@hide} */
- public static void dumpRules(PrintWriter fout, int rules) {
- fout.write("[");
- if ((rules & RULE_REJECT_METERED) != 0) {
- fout.write("REJECT_METERED");
- } else if ((rules & RULE_REJECT_ALL) != 0) {
- fout.write("REJECT_ALL");
- }
- fout.write("]");
- }
-
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 97b85e2..fdd34f5 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -471,7 +471,7 @@ public final class Debug
* </tbody>
* </table>
*/
- public String getMemoryStat(String statName) {
+ public String getMemoryStat(String statName) {
switch(statName) {
case "summary.java-heap":
return Integer.toString(getSummaryJavaHeap());
@@ -1538,7 +1538,13 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Retrieves information about this processes memory usages. This information is broken down by
- * how much is in use by dalivk, the native heap, and everything else.
+ * how much is in use by dalvik, the native heap, and everything else.
+ *
+ * <p><b>Note:</b> this method directly retrieves memory information for the give process
+ * from low-level data available to it. It may not be able to retrieve information about
+ * some protected allocations, such as graphics. If you want to be sure you can see
+ * all information about allocations by the process, use instead
+ * {@link android.app.ActivityManager#getProcessMemoryInfo(int[])}.</p>
*/
public static native void getMemoryInfo(MemoryInfo memoryInfo);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 7d48a9a..db68c29 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -447,10 +447,11 @@ public class SurfaceView extends View {
final boolean formatChanged = mFormat != mRequestedFormat;
final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
final boolean visibleChanged = mVisible != mRequestedVisible;
+ final boolean layoutSizeChanged = getWidth() != mLayout.width || getHeight() != mLayout.height;
if (force || creating || formatChanged || sizeChanged || visibleChanged
|| mLeft != mLocation[0] || mTop != mLocation[1]
- || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
+ || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded || layoutSizeChanged) {
if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 43c578f..dea004e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2355,7 +2355,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* 1 PFLAG3_APPLYING_INSETS
* 1 PFLAG3_FITTING_SYSTEM_WINDOWS
* 1 PFLAG3_NESTED_SCROLLING_ENABLED
- * 1 PFLAG3_ASSIST_BLOCKED
+ * 1 PFLAG3_SCROLL_INDICATOR_TOP
+ * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM
+ * 1 PFLAG3_SCROLL_INDICATOR_LEFT
+ * 1 PFLAG3_SCROLL_INDICATOR_RIGHT
+ * 1 PFLAG3_SCROLL_INDICATOR_START
+ * 1 PFLAG3_SCROLL_INDICATOR_END
+ * 1 PFLAG3_ASSIST_BLOCKED
* |-------|-------|-------|-------|
*/
@@ -2549,7 +2555,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* <p>Indicates that we are allowing {@link ViewStructure} to traverse
* into this view.<p>
*/
- static final int PFLAG3_ASSIST_BLOCKED = 0x100;
+ static final int PFLAG3_ASSIST_BLOCKED = 0x4000;
/**
* Always allow a user to over-scroll this view, provided it is a
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 2e0bf06..6bbebb7 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -16,6 +16,8 @@
package com.android.internal.app;
+import android.animation.ObjectAnimator;
+import android.annotation.NonNull;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
@@ -29,6 +31,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.database.DataSetObserver;
+import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Bundle;
@@ -46,13 +49,18 @@ import android.service.chooser.ChooserTargetService;
import android.service.chooser.IChooserTargetResult;
import android.service.chooser.IChooserTargetService;
import android.text.TextUtils;
+import android.util.FloatProperty;
import android.util.Log;
import android.util.Slog;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.View.MeasureSpec;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ListView;
@@ -80,6 +88,7 @@ public class ChooserActivity extends ResolverActivity {
private Intent mReferrerFillInIntent;
private ChooserListAdapter mChooserListAdapter;
+ private ChooserRowAdapter mChooserRowAdapter;
private final List<ChooserTargetServiceConnection> mServiceConnections = new ArrayList<>();
@@ -253,7 +262,9 @@ public class ChooserActivity extends ResolverActivity {
boolean alwaysUseOption) {
final ListView listView = adapterView instanceof ListView ? (ListView) adapterView : null;
mChooserListAdapter = (ChooserListAdapter) adapter;
- adapterView.setAdapter(new ChooserRowAdapter(mChooserListAdapter));
+ mChooserRowAdapter = new ChooserRowAdapter(mChooserListAdapter);
+ mChooserRowAdapter.registerDataSetObserver(new OffsetDataSetObserver(adapterView));
+ adapterView.setAdapter(mChooserRowAdapter);
if (listView != null) {
listView.setItemsCanFocus(true);
}
@@ -913,19 +924,103 @@ public class ChooserActivity extends ResolverActivity {
}
}
+ static class RowScale {
+ private static final int DURATION = 400;
+
+ float mScale;
+ ChooserRowAdapter mAdapter;
+ private final ObjectAnimator mAnimator;
+
+ public static final FloatProperty<RowScale> PROPERTY =
+ new FloatProperty<RowScale>("scale") {
+ @Override
+ public void setValue(RowScale object, float value) {
+ object.mScale = value;
+ object.mAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ public Float get(RowScale object) {
+ return object.mScale;
+ }
+ };
+
+ public RowScale(@NonNull ChooserRowAdapter adapter, float from, float to) {
+ mAdapter = adapter;
+ mScale = from;
+ if (from == to) {
+ mAnimator = null;
+ return;
+ }
+
+ mAnimator = ObjectAnimator.ofFloat(this, PROPERTY, from, to).setDuration(DURATION);
+ }
+
+ public RowScale setInterpolator(Interpolator interpolator) {
+ if (mAnimator != null) {
+ mAnimator.setInterpolator(interpolator);
+ }
+ return this;
+ }
+
+ public float get() {
+ return mScale;
+ }
+
+ public void startAnimation() {
+ if (mAnimator != null) {
+ mAnimator.start();
+ }
+ }
+
+ public void cancelAnimation() {
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
+ }
+ }
+
class ChooserRowAdapter extends BaseAdapter {
private ChooserListAdapter mChooserListAdapter;
private final LayoutInflater mLayoutInflater;
private final int mColumnCount = 4;
+ private RowScale[] mServiceTargetScale;
+ private final Interpolator mInterpolator;
public ChooserRowAdapter(ChooserListAdapter wrappedAdapter) {
mChooserListAdapter = wrappedAdapter;
mLayoutInflater = LayoutInflater.from(ChooserActivity.this);
+ mInterpolator = AnimationUtils.loadInterpolator(ChooserActivity.this,
+ android.R.interpolator.decelerate_quint);
+
wrappedAdapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
super.onChanged();
+ final int rcount = getServiceTargetRowCount();
+ if (mServiceTargetScale == null
+ || mServiceTargetScale.length != rcount) {
+ RowScale[] old = mServiceTargetScale;
+ int oldRCount = old != null ? old.length : 0;
+ mServiceTargetScale = new RowScale[rcount];
+ if (old != null && rcount > 0) {
+ System.arraycopy(old, 0, mServiceTargetScale, 0,
+ Math.min(old.length, rcount));
+ }
+
+ for (int i = rcount; i < oldRCount; i++) {
+ old[i].cancelAnimation();
+ }
+
+ for (int i = oldRCount; i < rcount; i++) {
+ final RowScale rs = new RowScale(ChooserRowAdapter.this, 0.f, 1.f)
+ .setInterpolator(mInterpolator);
+ mServiceTargetScale[i] = rs;
+ rs.startAnimation();
+ }
+ }
+
notifyDataSetChanged();
}
@@ -933,19 +1028,43 @@ public class ChooserActivity extends ResolverActivity {
public void onInvalidated() {
super.onInvalidated();
notifyDataSetInvalidated();
+ if (mServiceTargetScale != null) {
+ for (RowScale rs : mServiceTargetScale) {
+ rs.cancelAnimation();
+ }
+ }
}
});
}
+ private float getRowScale(int rowPosition) {
+ final int start = getCallerTargetRowCount();
+ final int end = start + getServiceTargetRowCount();
+ if (rowPosition >= start && rowPosition < end) {
+ return mServiceTargetScale[rowPosition - start].get();
+ }
+ return 1.f;
+ }
+
@Override
public int getCount() {
return (int) (
- Math.ceil((float) mChooserListAdapter.getCallerTargetCount() / mColumnCount)
- + Math.ceil((float) mChooserListAdapter.getServiceTargetCount() / mColumnCount)
+ getCallerTargetRowCount()
+ + getServiceTargetRowCount()
+ Math.ceil((float) mChooserListAdapter.getStandardTargetCount() / mColumnCount)
);
}
+ public int getCallerTargetRowCount() {
+ return (int) Math.ceil(
+ (float) mChooserListAdapter.getCallerTargetCount() / mColumnCount);
+ }
+
+ public int getServiceTargetRowCount() {
+ return (int) Math.ceil(
+ (float) mChooserListAdapter.getServiceTargetCount() / mColumnCount);
+ }
+
@Override
public Object getItem(int position) {
// We have nothing useful to return here.
@@ -959,33 +1078,67 @@ public class ChooserActivity extends ResolverActivity {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- final View[] holder;
+ final RowViewHolder holder;
if (convertView == null) {
holder = createViewHolder(parent);
} else {
- holder = (View[]) convertView.getTag();
+ holder = (RowViewHolder) convertView.getTag();
}
bindViewHolder(position, holder);
- // We keep the actual list item view as the last item in the holder array
- return holder[mColumnCount];
+ return holder.row;
}
- View[] createViewHolder(ViewGroup parent) {
- final View[] holder = new View[mColumnCount + 1];
-
+ RowViewHolder createViewHolder(ViewGroup parent) {
final ViewGroup row = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row,
parent, false);
+ final RowViewHolder holder = new RowViewHolder(row, mColumnCount);
+ final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+
for (int i = 0; i < mColumnCount; i++) {
- holder[i] = mChooserListAdapter.createView(row);
- row.addView(holder[i]);
+ final View v = mChooserListAdapter.createView(row);
+ v.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ startSelected(holder.itemIndex, false, true);
+ }
+ });
+ v.setOnLongClickListener(new OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ showAppDetails(
+ mChooserListAdapter.resolveInfoForPosition(holder.itemIndex, true));
+ return true;
+ }
+ });
+ row.addView(v);
+ holder.cells[i] = v;
+
+ // Force height to be a given so we don't have visual disruption during scaling.
+ LayoutParams lp = v.getLayoutParams();
+ v.measure(spec, spec);
+ if (lp == null) {
+ lp = new LayoutParams(LayoutParams.MATCH_PARENT, v.getMeasuredHeight());
+ row.setLayoutParams(lp);
+ } else {
+ lp.height = v.getMeasuredHeight();
+ }
+ }
+
+ // Pre-measure so we can scale later.
+ holder.measure();
+ LayoutParams lp = row.getLayoutParams();
+ if (lp == null) {
+ lp = new LayoutParams(LayoutParams.MATCH_PARENT, holder.measuredRowHeight);
+ row.setLayoutParams(lp);
+ } else {
+ lp.height = holder.measuredRowHeight;
}
row.setTag(holder);
- holder[mColumnCount] = row;
return holder;
}
- void bindViewHolder(int rowPosition, View[] holder) {
+ void bindViewHolder(int rowPosition, RowViewHolder holder) {
final int start = getFirstRowPosition(rowPosition);
final int startType = mChooserListAdapter.getPositionTargetType(start);
@@ -994,34 +1147,26 @@ public class ChooserActivity extends ResolverActivity {
end--;
}
- final ViewGroup row = (ViewGroup) holder[mColumnCount];
-
if (startType == ChooserListAdapter.TARGET_SERVICE) {
- row.setBackgroundColor(getColor(R.color.chooser_service_row_background_color));
+ holder.row.setBackgroundColor(
+ getColor(R.color.chooser_service_row_background_color));
} else {
- row.setBackground(null);
+ holder.row.setBackgroundColor(Color.TRANSPARENT);
+ }
+
+ final int oldHeight = holder.row.getLayoutParams().height;
+ holder.row.getLayoutParams().height = Math.max(1,
+ (int) (holder.measuredRowHeight * getRowScale(rowPosition)));
+ if (holder.row.getLayoutParams().height != oldHeight) {
+ holder.row.requestLayout();
}
for (int i = 0; i < mColumnCount; i++) {
- final View v = holder[i];
+ final View v = holder.cells[i];
if (start + i <= end) {
v.setVisibility(View.VISIBLE);
- final int itemIndex = start + i;
- mChooserListAdapter.bindView(itemIndex, v);
- v.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- startSelected(itemIndex, false, true);
- }
- });
- v.setOnLongClickListener(new OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- showAppDetails(
- mChooserListAdapter.resolveInfoForPosition(itemIndex, true));
- return true;
- }
- });
+ holder.itemIndex = start + i;
+ mChooserListAdapter.bindView(holder.itemIndex, v);
} else {
v.setVisibility(View.GONE);
}
@@ -1048,6 +1193,24 @@ public class ChooserActivity extends ResolverActivity {
}
}
+ static class RowViewHolder {
+ final View[] cells;
+ final ViewGroup row;
+ int measuredRowHeight;
+ int itemIndex;
+
+ public RowViewHolder(ViewGroup row, int cellCount) {
+ this.row = row;
+ this.cells = new View[cellCount];
+ }
+
+ public void measure() {
+ final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ row.measure(spec, spec);
+ measuredRowHeight = row.getMeasuredHeight();
+ }
+ }
+
static class ChooserTargetServiceConnection implements ServiceConnection {
private final DisplayResolveInfo mOriginalTarget;
private ComponentName mConnectedComponent;
@@ -1199,4 +1362,44 @@ public class ChooserActivity extends ResolverActivity {
mSelectedTarget = null;
}
}
+
+ class OffsetDataSetObserver extends DataSetObserver {
+ private final AbsListView mListView;
+ private int mCachedViewType = -1;
+ private View mCachedView;
+
+ public OffsetDataSetObserver(AbsListView listView) {
+ mListView = listView;
+ }
+
+ @Override
+ public void onChanged() {
+ if (mResolverDrawerLayout == null) {
+ return;
+ }
+
+ final int chooserTargetRows = mChooserRowAdapter.getServiceTargetRowCount();
+ int offset = 0;
+ for (int i = 0; i < chooserTargetRows; i++) {
+ final int pos = mChooserRowAdapter.getCallerTargetRowCount() + i;
+ final int vt = mChooserRowAdapter.getItemViewType(pos);
+ if (vt != mCachedViewType) {
+ mCachedView = null;
+ }
+ final View v = mChooserRowAdapter.getView(pos, mCachedView, mListView);
+ int height = ((RowViewHolder) (v.getTag())).measuredRowHeight;
+
+ offset += (int) (height * mChooserRowAdapter.getRowScale(pos) * chooserTargetRows);
+
+ if (vt >= 0) {
+ mCachedViewType = vt;
+ mCachedView = v;
+ } else {
+ mCachedViewType = -1;
+ }
+ }
+
+ mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
+ }
+ }
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 1710489..ba0912a 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -103,6 +103,8 @@ public class ResolverActivity extends Activity {
private ResolverComparator mResolverComparator;
private PickTargetOptionRequest mPickOptionRequest;
+ protected ResolverDrawerLayout mResolverDrawerLayout;
+
private boolean mRegistered;
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override public void onSomePackagesChanged() {
@@ -253,6 +255,7 @@ public class ResolverActivity extends Activity {
if (isVoiceInteraction()) {
rdl.setCollapsed(false);
}
+ mResolverDrawerLayout = rdl;
}
if (title == null) {
@@ -1570,7 +1573,10 @@ public class ResolverActivity extends Activity {
private void onBindView(View view, TargetInfo info) {
final ViewHolder holder = (ViewHolder) view.getTag();
- holder.text.setText(info.getDisplayLabel());
+ final CharSequence label = info.getDisplayLabel();
+ if (!TextUtils.equals(holder.text.getText(), label)) {
+ holder.text.setText(info.getDisplayLabel());
+ }
if (showsExtendedInfo(info)) {
holder.text2.setVisibility(View.VISIBLE);
holder.text2.setText(info.getExtendedInfo());
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 7679624..c4347f8 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -69,6 +69,12 @@ public class ResolverDrawerLayout extends ViewGroup {
private int mCollapsibleHeight;
private int mUncollapsibleHeight;
+ /**
+ * The height in pixels of reserved space added to the top of the collapsed UI;
+ * e.g. chooser targets
+ */
+ private int mCollapsibleHeightReserved;
+
private int mTopOffset;
private boolean mIsDragging;
@@ -153,12 +159,62 @@ public class ResolverDrawerLayout extends ViewGroup {
}
}
+ public void setCollapsibleHeightReserved(int heightPixels) {
+ final int oldReserved = mCollapsibleHeightReserved;
+ mCollapsibleHeightReserved = heightPixels;
+
+ final int dReserved = mCollapsibleHeightReserved - oldReserved;
+ if (dReserved != 0 && mIsDragging) {
+ mLastTouchY -= dReserved;
+ }
+
+ final int oldCollapsibleHeight = mCollapsibleHeight;
+ mCollapsibleHeight = Math.max(mCollapsibleHeight, getMaxCollapsedHeight());
+
+ if (updateCollapseOffset(oldCollapsibleHeight, !isDragging())) {
+ return;
+ }
+
+ invalidate();
+ }
+
private boolean isMoving() {
return mIsDragging || !mScroller.isFinished();
}
+ private boolean isDragging() {
+ return mIsDragging || getNestedScrollAxes() == SCROLL_AXIS_VERTICAL;
+ }
+
+ private boolean updateCollapseOffset(int oldCollapsibleHeight, boolean remainClosed) {
+ if (oldCollapsibleHeight == mCollapsibleHeight) {
+ return false;
+ }
+
+ if (isLaidOut()) {
+ final boolean isCollapsedOld = mCollapseOffset != 0;
+ if (remainClosed && (oldCollapsibleHeight < mCollapsibleHeight
+ && mCollapseOffset == oldCollapsibleHeight)) {
+ // Stay closed even at the new height.
+ mCollapseOffset = mCollapsibleHeight;
+ } else {
+ mCollapseOffset = Math.min(mCollapseOffset, mCollapsibleHeight);
+ }
+ final boolean isCollapsedNew = mCollapseOffset != 0;
+ if (isCollapsedOld != isCollapsedNew) {
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ }
+ } else {
+ // Start out collapsed at first unless we restored state for otherwise
+ mCollapseOffset = mOpenOnLayout ? 0 : mCollapsibleHeight;
+ }
+ return true;
+ }
+
private int getMaxCollapsedHeight() {
- return isSmallCollapsed() ? mMaxCollapsedHeightSmall : mMaxCollapsedHeight;
+ return (isSmallCollapsed() ? mMaxCollapsedHeightSmall : mMaxCollapsedHeight)
+ + mCollapsibleHeightReserved;
}
public void setOnDismissedListener(OnDismissedListener listener) {
@@ -676,7 +732,7 @@ public class ResolverDrawerLayout extends ViewGroup {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.alwaysShow && child.getVisibility() != GONE) {
measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
- heightUsed += lp.topMargin + child.getMeasuredHeight() + lp.bottomMargin;
+ heightUsed += getHeightUsed(child);
}
}
@@ -688,7 +744,7 @@ public class ResolverDrawerLayout extends ViewGroup {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (!lp.alwaysShow && child.getVisibility() != GONE) {
measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
- heightUsed += lp.topMargin + child.getMeasuredHeight() + lp.bottomMargin;
+ heightUsed += getHeightUsed(child);
}
}
@@ -697,30 +753,43 @@ public class ResolverDrawerLayout extends ViewGroup {
heightUsed - alwaysShowHeight - getMaxCollapsedHeight());
mUncollapsibleHeight = heightUsed - mCollapsibleHeight;
- if (isLaidOut()) {
- final boolean isCollapsedOld = mCollapseOffset != 0;
- if (oldCollapsibleHeight < mCollapsibleHeight
- && mCollapseOffset == oldCollapsibleHeight) {
- // Stay closed even at the new height.
- mCollapseOffset = mCollapsibleHeight;
- } else {
- mCollapseOffset = Math.min(mCollapseOffset, mCollapsibleHeight);
- }
- final boolean isCollapsedNew = mCollapseOffset != 0;
- if (isCollapsedOld != isCollapsedNew) {
- notifyViewAccessibilityStateChangedIfNeeded(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
- }
- } else {
- // Start out collapsed at first unless we restored state for otherwise
- mCollapseOffset = mOpenOnLayout ? 0 : mCollapsibleHeight;
- }
+ updateCollapseOffset(oldCollapsibleHeight, !isDragging());
mTopOffset = Math.max(0, heightSize - heightUsed) + (int) mCollapseOffset;
setMeasuredDimension(sourceWidth, heightSize);
}
+ private int getHeightUsed(View child) {
+ // This method exists because we're taking a fast path at measuring ListViews that
+ // lets us get away with not doing the more expensive wrap_content measurement which
+ // imposes double child view measurement costs. If we're looking at a ListView, we can
+ // check against the lowest child view plus padding and margin instead of the actual
+ // measured height of the ListView. This lets the ListView hang off the edge when
+ // all of the content would fit on-screen.
+
+ int heightUsed = child.getMeasuredHeight();
+ if (child instanceof AbsListView) {
+ final AbsListView lv = (AbsListView) child;
+ final int lvPaddingBottom = lv.getPaddingBottom();
+
+ int lowest = 0;
+ for (int i = 0, N = lv.getChildCount(); i < N; i++) {
+ final int bottom = lv.getChildAt(i).getBottom() + lvPaddingBottom;
+ if (bottom > lowest) {
+ lowest = bottom;
+ }
+ }
+
+ if (lowest < heightUsed) {
+ heightUsed = lowest;
+ }
+ }
+
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ return lp.topMargin + heightUsed + lp.bottomMargin;
+ }
+
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int width = getWidth();