Merge "Remove unused permissions, libs"
diff --git a/res/drawable-hdpi/default_avatar_white.png b/res/drawable-hdpi/default_avatar_white.png
new file mode 100644
index 0000000..711286c
--- /dev/null
+++ b/res/drawable-hdpi/default_avatar_white.png
Binary files differ
diff --git a/res/drawable-mdpi/default_avatar_white.png b/res/drawable-mdpi/default_avatar_white.png
new file mode 100644
index 0000000..0983eb0
--- /dev/null
+++ b/res/drawable-mdpi/default_avatar_white.png
Binary files differ
diff --git a/res/drawable-xhdpi/default_avatar_white.png b/res/drawable-xhdpi/default_avatar_white.png
new file mode 100644
index 0000000..f645ff2
--- /dev/null
+++ b/res/drawable-xhdpi/default_avatar_white.png
Binary files differ
diff --git a/res/drawable-xxhdpi/default_avatar_white.png b/res/drawable-xxhdpi/default_avatar_white.png
new file mode 100644
index 0000000..b92f026
--- /dev/null
+++ b/res/drawable-xxhdpi/default_avatar_white.png
Binary files differ
diff --git a/res/drawable/default_avatar_white.xml b/res/drawable/default_avatar_white.xml
new file mode 100644
index 0000000..9bc5cbf
--- /dev/null
+++ b/res/drawable/default_avatar_white.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<inset
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/default_avatar_white"
+ android:insetRight="102dp"
+ android:insetLeft="102dp" />
\ No newline at end of file
diff --git a/res/layout-land/quickcontact_activity.xml b/res/layout-land/quickcontact_activity.xml
index 65fcd7d..9a07698 100644
--- a/res/layout-land/quickcontact_activity.xml
+++ b/res/layout-land/quickcontact_activity.xml
@@ -26,6 +26,7 @@
<View
android:layout_width="match_parent"
android:layout_height="@dimen/quickcontact_starting_empty_height"
+ android:contentDescription="@string/quickcontact_transparent_view_description"
android:id="@+id/transparent_view" />
<LinearLayout
diff --git a/res/layout/quickcontact_activity.xml b/res/layout/quickcontact_activity.xml
index 7b81ea2..008062b 100644
--- a/res/layout/quickcontact_activity.xml
+++ b/res/layout/quickcontact_activity.xml
@@ -27,6 +27,7 @@
<View
android:layout_width="match_parent"
android:layout_height="@dimen/quickcontact_starting_empty_height"
+ android:contentDescription="@string/quickcontact_transparent_view_description"
android:id="@+id/transparent_view" />
<include layout="@layout/quickcontact_header" />
diff --git a/res/layout/quickcontact_header.xml b/res/layout/quickcontact_header.xml
index 55b23c9..0c51746 100644
--- a/res/layout/quickcontact_header.xml
+++ b/res/layout/quickcontact_header.xml
@@ -14,10 +14,14 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
+<!-- Needs a non null background in for elevation to work on this View. This will *not* cause an
+ additional draw since the background is transparent. -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:background="#00000000"
android:id="@+id/toolbar_parent">
<com.android.contacts.widget.QuickContactImageView
@@ -27,8 +31,9 @@
android:scaleType="centerCrop"
android:contentDescription="@string/description_contact_photo" />
- <!-- Need to set a non null background on Toolbar in order for MenuItem
- ripples to be drawn on this view, instead of another-->
+ <!-- Need to set a non null background on Toolbar in order for MenuItem ripples to be drawn on
+ this view, instead of another. This will *not* cause an additional draw since the
+ background is transparent.-->
<Toolbar
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
@@ -43,6 +48,9 @@
android:ellipsize="end"
android:layout_gravity="bottom"
android:textSize="@dimen/quickcontact_maximum_title_size"
+ android:layout_marginStart="@dimen/quickcontact_title_initial_margin"
+ android:layout_marginEnd="@dimen/quickcontact_title_initial_margin"
+ android:layout_marginBottom="@dimen/quickcontact_title_initial_margin"
android:id="@+id/large_title"/>
-</FrameLayout>
\ No newline at end of file
+</FrameLayout>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9d8ba70..5a2f7ab 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -20,6 +20,8 @@
<dimen name="quickcontact_starting_empty_height">150dp</dimen>
<!-- Initial size of QuickContact's title size -->
<dimen name="quickcontact_maximum_title_size">36dp</dimen>
+ <!-- When QC is uncollapsed, the title has this much margin on its left, right and bottom -->
+ <dimen name="quickcontact_title_initial_margin">16dp</dimen>
<!-- Top padding of the entire contact editor -->
<dimen name="editor_padding_top">0dip</dimen>
@@ -142,19 +144,18 @@
<!-- Margins for ExpandingEntryCardView -->
- <dimen name="expanding_entry_card_marginStart">8dp</dimen>
- <dimen name="expanding_entry_card_marginEnd">8dp</dimen>
- <dimen name="expanding_entry_card_marginBottom">8dp</dimen>
+ <dimen name="expanding_entry_card_marginStart">12dp</dimen>
+ <dimen name="expanding_entry_card_marginEnd">12dp</dimen>
+ <dimen name="expanding_entry_card_marginBottom">12dp</dimen>
+
+ <!-- Top margin for the communication card, used to add space from header. -->
+ <dimen name="communication_card_marginTop">12dp</dimen>
<!-- Elevation of an ExpandingEntryCard, for the sake of shadow casting -->
<dimen name="expanding_entry_card_elevation">1dp</dimen>
<!-- Elevation of the QuickContact's Toolbar, for the sake of shadow casting -->
<dimen name="quick_contact_toolbar_elevation">4.5dp</dimen>
- <!-- Top margin for the communication card, used to add space from header. -->
- <dimen name="communication_card_marginTop">8dp</dimen>
-
-
<!-- Size of the title text for a ExpandingEntryCardView -->
<dimen name="expanding_entry_card_title_text_size">16sp</dimen>
<!-- Padding for the title text for a ExpandingEntryCardView -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index afd0f40..434a62b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -309,6 +309,9 @@
<!-- Shown as a toast when the user taps on a QuickContact icon, and no application
was found that could perform the selected action. [CHAR LIMIT=NONE] -->
<string name="quickcontact_missing_app">No app was found to handle this action.</string>
+ <!-- Content description for the transparent view above the visible section of QuickContacts.
+ Clicking this view causes Quick Contacts to close. [CHAR LIMIT=NONE] -->
+ <string name="quickcontact_transparent_view_description">Click to return to previous screen</string>
<!-- Shown as a toast when the user attempts an action (add contact, edit
contact, etc) and no application was found that could perform that
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 99d8094..f0c7241 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -689,6 +689,7 @@
* type is also sorted, based off of {super primary, primary, times used} in that order.
*/
final List<Action> topActions = new ArrayList<>();
+ final List<Action> allActions = new ArrayList<>();
for (List<Action> mimeTypeActions : mActions.values()) {
Collections.sort(mimeTypeActions, new Comparator<Action>() {
@Override
@@ -716,6 +717,9 @@
}
});
topActions.add(mimeTypeActions.get(0));
+ // Add all the other actions and remove the top one
+ allActions.addAll(mimeTypeActions);
+ allActions.remove(mimeTypeActions.get(0));
}
// topActions now contains the top action for each mimetype. This list now needs to be
@@ -762,6 +766,7 @@
});
entries.addAll(actionsToEntries(topActions));
+ entries.addAll(actionsToEntries(allActions));
Trace.endSection();
}
diff --git a/src/com/android/contacts/widget/MultiShrinkScroller.java b/src/com/android/contacts/widget/MultiShrinkScroller.java
index 3666420..18f032a 100644
--- a/src/com/android/contacts/widget/MultiShrinkScroller.java
+++ b/src/com/android/contacts/widget/MultiShrinkScroller.java
@@ -17,6 +17,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
+import android.os.Trace;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Display;
@@ -85,6 +86,10 @@
private int mMinimumHeaderHeight;
private int mIntermediateHeaderHeight;
private int mMaximumHeaderTextSize;
+ private int mCollapsedTitleBottomMargin;
+ private int mCollapsedTitleStartMargin;
+ private int mMinimumPortraitHeaderHeight;
+ private int mMaximumPortraitHeaderHeight;
private final Scroller mScroller;
private final EdgeEffect mEdgeGlowBottom;
@@ -92,10 +97,9 @@
private final int mMaximumVelocity;
private final int mMinimumVelocity;
private final int mTransparentStartHeight;
+ private final int mMaximumTitleMargin;
private final float mToolbarElevation;
private final boolean mIsTwoPanel;
- final Rect mLargeTextViewRect = new Rect();
- final Rect mInvisiblePlaceholderTextViewRect = new Rect();
// Objects used to perform color filtering on the header. These are stored as fields for
// the sole purpose of avoiding "new" operations inside animation loops.
@@ -186,13 +190,18 @@
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
mTransparentStartHeight = (int) getResources().getDimension(
R.dimen.quickcontact_starting_empty_height);
- mToolbarElevation = mContext.getResources().getDimension(
+ mToolbarElevation = getResources().getDimension(
R.dimen.quick_contact_toolbar_elevation);
- mIsTwoPanel = mContext.getResources().getBoolean(R.bool.quickcontact_two_panel);
+ mIsTwoPanel = getResources().getBoolean(R.bool.quickcontact_two_panel);
+ mMaximumTitleMargin = (int) getResources().getDimension(
+ R.dimen.quickcontact_title_initial_margin);
final TypedArray attributeArray = context.obtainStyledAttributes(
new int[]{android.R.attr.actionBarSize});
mMinimumHeaderHeight = attributeArray.getDimensionPixelSize(0, 0);
+ // This value is approximately equal to the portrait ActionBar size. It isn't exactly the
+ // same, since the landscape and portrait ActionBar sizes can be different.
+ mMinimumPortraitHeaderHeight = mMinimumHeaderHeight;
attributeArray.recycle();
}
@@ -227,6 +236,7 @@
mIntermediateHeaderHeight = (int) (mMaximumHeaderHeight
* INTERMEDIATE_HEADER_HEIGHT_RATIO);
}
+ mMaximumPortraitHeaderHeight = Math.min(windowSize.x, windowSize.y);
setHeaderHeight(mIntermediateHeaderHeight);
SchedulingUtils.doOnPreDraw(this, /* drawNextFrame = */ false, new Runnable() {
@@ -251,6 +261,7 @@
mPhotoViewContainer.setLayoutParams(layoutParams);
}
+ calculateCollapsedLargeTitlePadding();
updateHeaderTextSize();
}
});
@@ -712,7 +723,7 @@
// Keep the text at maximum size since the header is smaller than threshold.
mLargeTextView.setScaleX(1);
mLargeTextView.setScaleY(1);
- configureLargeTitlePadding();
+ setInterpolatedTitleMargin(1);
return;
}
final float ratio = (toolbarHeight - mMinimumHeaderHeight)
@@ -723,40 +734,55 @@
mLargeTextView.setScaleX(scale);
mLargeTextView.setScaleY(scale);
- configureLargeTitlePadding();
+ setInterpolatedTitleMargin(ratio);
}
/**
- * Configure the padding around mLargeTextView so that it will look appropriate once it
+ * Calculate the padding around mLargeTextView so that it will look appropriate once it
* finishes moving into its target location/size.
*/
- private void configureLargeTitlePadding() {
- mToolbar.getBoundsOnScreen(mLargeTextViewRect);
- mInvisiblePlaceholderTextView.getBoundsOnScreen(mInvisiblePlaceholderTextViewRect);
- final int neededPaddingStart;
+ private void calculateCollapsedLargeTitlePadding() {
+ final Rect largeTextViewRect = new Rect();
+ final Rect invisiblePlaceholderTextViewRect = new Rect();
+ mToolbar.getBoundsOnScreen(largeTextViewRect);
+ mInvisiblePlaceholderTextView.getBoundsOnScreen(invisiblePlaceholderTextViewRect);
if (isLayoutRtl()) {
- neededPaddingStart = mInvisiblePlaceholderTextViewRect.right - mLargeTextViewRect.right;
+ mCollapsedTitleStartMargin = invisiblePlaceholderTextViewRect.right
+ - largeTextViewRect.right;
} else {
- neededPaddingStart = mInvisiblePlaceholderTextViewRect.left - mLargeTextViewRect.left;
+ mCollapsedTitleStartMargin = invisiblePlaceholderTextViewRect.left
+ - largeTextViewRect.left;
}
// Distance between top of toolbar to the center of the target rectangle.
final int desiredTopToCenter = (
- mInvisiblePlaceholderTextViewRect.top + mInvisiblePlaceholderTextViewRect.bottom)
- / 2 - mLargeTextViewRect.top;
- // Additional padding needed on the mLargeTextView so that it has the same amount of
+ invisiblePlaceholderTextViewRect.top + invisiblePlaceholderTextViewRect.bottom)
+ / 2 - largeTextViewRect.top;
+ // Padding needed on the mLargeTextView so that it has the same amount of
// padding as the target rectangle.
- final int additionalBottomPaddingNeeded = desiredTopToCenter - mLargeTextView.getHeight()
- / 2;
+ mCollapsedTitleBottomMargin = desiredTopToCenter - mLargeTextView.getHeight() / 2;
+ }
+ /**
+ * Interpolate the title's margin size. When {@param x}=1, use the maximum title margins.
+ * When {@param x}=0, use the margin values taken from {@link #mInvisiblePlaceholderTextView}.
+ */
+ private void setInterpolatedTitleMargin(float x) {
final FrameLayout.LayoutParams layoutParams
= (FrameLayout.LayoutParams) mLargeTextView.getLayoutParams();
- layoutParams.bottomMargin = additionalBottomPaddingNeeded;
- layoutParams.setMarginStart(neededPaddingStart);
+ layoutParams.bottomMargin = (int) (mCollapsedTitleBottomMargin * (1 - x)
+ + mMaximumTitleMargin * x) ;
+ layoutParams.setMarginStart((int) (mCollapsedTitleStartMargin * (1 - x)
+ + mMaximumTitleMargin * x));
mLargeTextView.setLayoutParams(layoutParams);
}
private void updatePhotoTintAndDropShadow() {
+ // Let's keep an eye on how long this method takes to complete. Right now, it takes ~0.2ms
+ // on a Nexus 5. If it starts to get much slower, there are a number of easy optimizations
+ // available.
+ Trace.beginSection("updatePhotoTintAndDropShadow");
+
// We need to use toolbarLayoutParams to determine the height, since the layout
// params can be updated before the height change is reflected inside the View#getHeight().
final int toolbarHeight = mToolbar.getLayoutParams().height;
@@ -770,22 +796,17 @@
// Reuse an existing mColorFilter (to avoid GC pauses) to change the photo's tint.
mPhotoView.clearColorFilter();
+ // Ratio of current size to maximum size of the header.
final float ratio;
- final float intermediateRatio;
+ // The value that "ratio" will have when the header is at its starting/intermediate size.
+ final float intermediateRatio = calculateHeightRatio((int)
+ (mMaximumPortraitHeaderHeight * INTERMEDIATE_HEADER_HEIGHT_RATIO));
if (!mIsTwoPanel) {
- // Ratio of current size to maximum size of the header.
- ratio = (toolbarHeight - mMinimumHeaderHeight)
- / (float) (mMaximumHeaderHeight - mMinimumHeaderHeight) ;
- // The value that "ratio" will have when the header is at its
- // starting/intermediate size.
- intermediateRatio = (mIntermediateHeaderHeight - mMinimumHeaderHeight)
- / (float) (mMaximumHeaderHeight - mMinimumHeaderHeight);
+ ratio = calculateHeightRatio(toolbarHeight);
} else {
- // Set ratio and intermediateRatio to the same arbitrary value, so that
- // the math below considers us to be in the intermediate position. The specific
- // values are not very important.
- ratio = 0.5f;
- intermediateRatio = 0.5f;
+ // We want the ratio and intermediateRatio to have the *approximate* values
+ // they would have in portrait mode when at the intermediate position.
+ ratio = intermediateRatio;
}
final float linearBeforeMiddle = Math.max(1 - (1 - ratio) / intermediateRatio, 0);
@@ -802,11 +823,16 @@
final float colorAlpha;
if (mPhotoView.isBasedOffLetterTile()) {
// Since the letter tile only has white and grey, tint it more slowly. Otherwise
- // it will be completely invisible before we reach the intermediate point.
- final float SLOWING_FACTOR = 1.6f;
+ // it will be completely invisible before we reach the intermediate point. The values
+ // for TILE_EXPONENT and slowingFactor are chosen to achieve DESIRED_INTERMEDIATE_ALPHA
+ // at the intermediate/starting position.
+ final float DESIRED_INTERMEDIATE_ALPHA = 0.9f;
+ final float TILE_EXPONENT = 1.5f;
+ final float slowingFactor = (float) ((1 - intermediateRatio) / intermediateRatio
+ / (1 - Math.pow(1 - DESIRED_INTERMEDIATE_ALPHA, 1/TILE_EXPONENT)));
float linearBeforeMiddleish = Math.max(1 - (1 - ratio) / intermediateRatio
- / SLOWING_FACTOR, 0);
- colorAlpha = 1 - (float) Math.pow(linearBeforeMiddleish, EXPONENT_ALMOST_ONE);
+ / slowingFactor, 0);
+ colorAlpha = 1 - (float) Math.pow(linearBeforeMiddleish, TILE_EXPONENT);
mColorMatrix.postConcat(alphaMatrix(colorAlpha, mHeaderTintColor));
} else {
colorAlpha = 1 - semiLinearBeforeMiddle;
@@ -817,7 +843,14 @@
mPhotoView.setColorFilter(mColorFilter);
// Tell the photo view what tint we are trying to achieve. Depending on the type of
// drawable used, the photo view may or may not use this tint.
- mPhotoView.setTint(((int) (0xFF * colorAlpha)) << 24 | (mHeaderTintColor & 0xffffff));
+ mPhotoView.setTint(mHeaderTintColor);
+
+ Trace.endSection();
+ }
+
+ private float calculateHeightRatio(int height) {
+ return (height - mMinimumPortraitHeaderHeight)
+ / (float) (mMaximumPortraitHeaderHeight - mMinimumPortraitHeaderHeight);
}
/**
diff --git a/src/com/android/contacts/widget/QuickContactImageView.java b/src/com/android/contacts/widget/QuickContactImageView.java
index 9dbf85e..987b27d 100644
--- a/src/com/android/contacts/widget/QuickContactImageView.java
+++ b/src/com/android/contacts/widget/QuickContactImageView.java
@@ -1,28 +1,27 @@
package com.android.contacts.widget;
-
import com.android.contacts.common.lettertiles.LetterTileDrawable;
import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Xfermode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
+import com.android.contacts.R;
+
/**
- * An {@link ImageView} designed to display QuickContact's contact photo. In addition to
- * supporting {@link ImageView#setColorFilter} this also performs a second color blending with
- * the tint set in {@link #setTint}. This requires a second draw pass.
+ * An {@link ImageView} designed to display QuickContact's contact photo. When requested to draw
+ * {@link LetterTileDrawable}'s, this class instead draws a different default avatar drawable.
+ *
+ * In addition to supporting {@link ImageView#setColorFilter} this also supports a {@link #setTint}
+ * method.
+ *
+ * This entire class can be deleted once use of LetterTileDrawable is no longer used
+ * inside QuickContactsActivity at all.
*/
public class QuickContactImageView extends ImageView {
- private Xfermode mMode = new PorterDuffXfermode(Mode.MULTIPLY);
- private int mTintColor;
- private BitmapDrawable mBitmapDrawable;
private Drawable mOriginalDrawable;
public QuickContactImageView(Context context) {
@@ -43,7 +42,11 @@
}
public void setTint(int color) {
- mTintColor = color;
+ if (isBasedOffLetterTile()) {
+ setBackgroundColor(color);
+ } else {
+ setBackground(null);
+ }
postInvalidate();
}
@@ -55,31 +58,24 @@
public void setImageDrawable(Drawable drawable) {
// There is no way to avoid all this casting. Blending modes aren't equally
// supported for all drawable types.
+ final BitmapDrawable bitmapDrawable;
if (drawable == null || drawable instanceof BitmapDrawable) {
- mBitmapDrawable = (BitmapDrawable) drawable;
+ bitmapDrawable = (BitmapDrawable) drawable;
+ setScaleType(ScaleType.CENTER_CROP);
} else if (drawable instanceof LetterTileDrawable) {
- // TODO: set a desired hardcoded BitmapDrawable here
- mBitmapDrawable = null;
+ bitmapDrawable = (BitmapDrawable) getResources().getDrawable(
+ R.drawable.default_avatar_white);
+ setScaleType(ScaleType.CENTER);
} else {
throw new IllegalArgumentException("Does not support this type of drawable");
}
mOriginalDrawable = drawable;
- super.setImageDrawable(mBitmapDrawable);
+ super.setImageDrawable(bitmapDrawable);
}
@Override
public Drawable getDrawable() {
return mOriginalDrawable;
}
-
- @Override
- protected void onDraw(Canvas canvas) {
- if (isBasedOffLetterTile()) {
- // The LetterTileDrawable's bitmaps have a lot of pixels with alpha=0. These
- // look stupid unless we fill in the background and use a different blending mode.
- canvas.drawColor(((LetterTileDrawable) mOriginalDrawable).getColor());
- }
- super.onDraw(canvas);
- }
}