DeepShortcut - show loading placeholder before content is available.

Sometimes the deep shortcuts can take time to load, show an initial loading
state before any text is set.

Note: changed singleLine to lines=1 as the former causes issues with RTL
layout and is deprecated.

Bug: 78620208
Tested: manual test on pixel 3

Change-Id: I782addb8d64425a1a95cee4f104fc0bd44809815
This commit is contained in:
Zak Cohen 2018-10-24 13:26:47 -07:00
parent 2c89278895
commit cc4c61472e
6 changed files with 129 additions and 2 deletions

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2017 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.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="?attr/popupColorSecondary"/>
<foreground android:drawable="?attr/popupColorSecondary"/>
</adaptive-icon>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?attr/popupColorSecondary" />
<corners android:radius="8dp" />
<size android:height="16dp" />
</shape>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="?attr/popupColorSecondary" />
<size
android:height="32dp"
android:width="32dp" />
</shape>

View File

@ -43,7 +43,8 @@
android:layout_width="@dimen/deep_shortcut_icon_size"
android:layout_height="@dimen/deep_shortcut_icon_size"
android:layout_marginStart="@dimen/popup_padding_start"
android:layout_gravity="start|center_vertical" />
android:layout_gravity="start|center_vertical"
android:background="@drawable/ic_deepshortcut_placeholder"/>
<View
android:id="@+id/divider"

View File

@ -144,7 +144,7 @@
<item name="android:layout_gravity">center</item>
<item name="android:focusable">true</item>
<item name="android:gravity">center_horizontal</item>
<item name="android:singleLine">true</item>
<item name="android:lines">1</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:fontFamily">sans-serif-condensed</item>
<item name="android:defaultFocusHighlightEnabled">false</item>

View File

@ -18,8 +18,10 @@ package com.android.launcher3.shortcuts;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Toast;
@ -38,6 +40,10 @@ public class DeepShortcutTextView extends BubbleTextView {
private Toast mInstructionToast;
private boolean mShowLoadingState;
private Drawable mLoadingStatePlaceholder;
private final Rect mLoadingStateBounds = new Rect();
public DeepShortcutTextView(Context context) {
this(context, null, 0);
}
@ -53,6 +59,7 @@ public class DeepShortcutTextView extends BubbleTextView {
mDragHandleWidth = resources.getDimensionPixelSize(R.dimen.popup_padding_end)
+ resources.getDimensionPixelSize(R.dimen.deep_shortcut_drag_handle_size)
+ resources.getDimensionPixelSize(R.dimen.deep_shortcut_drawable_padding) / 2;
showLoadingState(true);
}
@Override
@ -63,6 +70,25 @@ public class DeepShortcutTextView extends BubbleTextView {
if (!Utilities.isRtl(getResources())) {
mDragHandleBounds.offset(getMeasuredWidth() - mDragHandleBounds.width(), 0);
}
setLoadingBounds();
}
private void setLoadingBounds() {
if (mLoadingStatePlaceholder == null) {
return;
}
mLoadingStateBounds.set(
0,
0,
getMeasuredWidth() - mDragHandleWidth - getPaddingStart(),
mLoadingStatePlaceholder.getIntrinsicHeight());
mLoadingStateBounds.offset(
Utilities.isRtl(getResources()) ? mDragHandleWidth : getPaddingStart(),
(int) ((getMeasuredHeight() - mLoadingStatePlaceholder.getIntrinsicHeight())
/ 2.0f)
);
mLoadingStatePlaceholder.setBounds(mLoadingStateBounds);
}
@Override
@ -70,6 +96,15 @@ public class DeepShortcutTextView extends BubbleTextView {
// The icon is drawn in a separate view.
}
@Override
public void setText(CharSequence text, BufferType type) {
super.setText(text, type);
if (!TextUtils.isEmpty(text)) {
showLoadingState(false);
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
@ -88,6 +123,34 @@ public class DeepShortcutTextView extends BubbleTextView {
return super.performClick();
}
@Override
public void onDraw(Canvas canvas) {
if (!mShowLoadingState) {
super.onDraw(canvas);
return;
}
mLoadingStatePlaceholder.draw(canvas);
}
private void showLoadingState(boolean loading) {
if (loading == mShowLoadingState) {
return;
}
mShowLoadingState = loading;
if (loading) {
mLoadingStatePlaceholder = getContext().getDrawable(
R.drawable.deep_shortcuts_text_placeholder);
setLoadingBounds();
} else {
mLoadingStatePlaceholder = null;
}
invalidate();
}
private void showToast() {
if (mInstructionToast != null) {
mInstructionToast.cancel();