Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 516bb587 authored by Miranda Kephart's avatar Miranda Kephart Committed by Android (Google) Code Review
Browse files

Merge "Add AiAi overview chips to Launcher" into ub-launcher3-master

parents ccf00ab0 cd5beb3e
Loading
Loading
Loading
Loading
+0 −55
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
     Copyright (C) 2019 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.
-->
<com.android.quickstep.hints.HintView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="@dimen/chip_hint_height"
    android:layout_gravity="center_horizontal|bottom"
    android:paddingStart="@dimen/chip_hint_start_padding"
    android:paddingEnd="@dimen/chip_hint_end_padding"
    android:background="@drawable/chip_hint_background_light"
    android:gravity="center"
    android:layout_marginHorizontal="@dimen/chip_hint_horizontal_margin"
    android:orientation="horizontal"
    android:elevation="@dimen/chip_hint_elevation"
    android:layoutDirection="ltr">

    <ImageView
        android:id="@+id/icon"
        android:layout_width="@dimen/chip_icon_size"
        android:layout_height="@dimen/chip_icon_size"
        android:visibility="gone"
        android:scaleType="fitCenter"
        android:adjustViewBounds="true"
        android:contentDescription="@null"/>

    <TextView
        android:id="@+id/label"
        android:layout_width="wrap_content"
        android:layout_height="@dimen/chip_text_height"
        android:paddingTop="@dimen/chip_text_top_padding"
        android:paddingStart="@dimen/chip_text_start_padding"
        android:fontFamily="google-sans-medium"
        android:textAlignment="textStart"
        android:singleLine="true"
        android:textColor="@color/chip_hint_foreground_color"
        android:textSize="@dimen/chip_text_size"
        android:ellipsize="none"
        android:includeFontPadding="true"/>


</com.android.quickstep.hints.HintView>
 No newline at end of file
+3 −2
Original line number Diff line number Diff line
@@ -14,9 +14,10 @@
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<com.android.quickstep.hints.HintsContainer
<com.android.quickstep.hints.ChipsContainer
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_height="@dimen/chip_hint_height"
    android:layout_gravity="bottom"
    android:gravity="center_horizontal"
    android:orientation="horizontal"/>
 No newline at end of file
+72 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.quickstep.hints;

import android.content.Context;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.view.View;
import android.widget.FrameLayout;

public class ChipsContainer extends FrameLayout {

    private static final String TAG = "ChipsContainer";

    public static final FloatProperty<ChipsContainer> HINT_VISIBILITY =
            new FloatProperty<ChipsContainer>("hint_visibility") {
                @Override
                public void setValue(ChipsContainer chipsContainer, float v) {
                    chipsContainer.setHintVisibility(v);
                }

                @Override
                public Float get(ChipsContainer chipsContainer) {
                    return chipsContainer.mHintVisibility;
                }
            };

    private float mHintVisibility;

    public ChipsContainer(Context context) {
        super(context);
    }

    public ChipsContainer(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ChipsContainer(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public ChipsContainer(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public void setView(View v) {
        removeAllViews();
        addView(v);
    }

    public void setHintVisibility(float v) {
        if (v == 1) {
            setVisibility(VISIBLE);
        } else {
            setVisibility(GONE);
        }
        mHintVisibility = v;
    }
}
+0 −218
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.quickstep.hints;

import static com.android.quickstep.hints.UiHintListenerConstants.HINTS_KEY;
import static com.android.quickstep.hints.UiHintListenerConstants.ON_HINTS_RETURNED_CODE;
import static com.android.quickstep.hints.UiInterfaceConstants.REQUEST_HINTS_CODE;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Log;
import android.view.LayoutInflater;
import android.widget.LinearLayout;

import androidx.annotation.Nullable;

import com.android.launcher3.R;

import java.util.ArrayList;

public class HintsContainer extends LinearLayout {

    private static final String TAG = "HintsView";

    public static final FloatProperty<HintsContainer> HINT_VISIBILITY =
            new FloatProperty<HintsContainer>("hint_visibility") {
                @Override
                public void setValue(HintsContainer hintsContainer, float v) {
                    hintsContainer.setHintVisibility(v);
                }

                @Override
                public Float get(HintsContainer hintsContainer) {
                    return hintsContainer.mHintVisibility;
                }
            };

    private static Intent mServiceIntent =
            new Intent("com.android.systemui.action.UI_PULL_INTERFACE")
                    .setClassName(
                            "com.android.systemui.navbarhint",
                            "com.android.systemui.navbarhint.service.HintService");

    @Nullable
    private Messenger mHintServiceInterface;
    private UiHintListener mUiHintListener;
    private boolean mBound = false;
    private float mHintVisibility;

    private final ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            mHintServiceInterface = new Messenger(iBinder);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mHintServiceInterface = null;
            attemptBinding();
        }

        @Override
        public void onBindingDied(ComponentName componentName) {
            mHintServiceInterface = null;
            attemptBinding();
        }
    };

    public HintsContainer(Context context) {
        super(context);
    }

    public HintsContainer(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public HintsContainer(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public HintsContainer(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (mUiHintListener == null) {
            mUiHintListener = new UiHintListener(this);
        }
        if (!mBound) {
            attemptBinding();
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        if (mBound) {
            getContext().unbindService(mServiceConnection);
            mBound = false;
        }
        super.onDetachedFromWindow();
    }

    public void setHintVisibility(float v) {
        if (v == 1) {
            getHints();
            setVisibility(VISIBLE);
        } else {
            setVisibility(GONE);
        }
        mHintVisibility = v;
    }

    private void attemptBinding() {
        if (mBound) {
            getContext().unbindService(mServiceConnection);
            mBound = false;
        }
        boolean success = getContext().bindService(mServiceIntent,
                mServiceConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
        if (success) {
            mBound = true;
        } else {
            Log.w(TAG, "Binding to hint supplier failed");
        }
    }
    
    private void sendOnHintTap(Bundle hint) {
        if (mHintServiceInterface != null) {
            Message msg = Message.obtain(null, UiInterfaceConstants.ON_HINT_TAP_CODE);
            Bundle data = new Bundle();
            data.putString(UiInterfaceConstants.HINT_ID_KEY, HintUtil.getId(hint));
            data.putInt(UiInterfaceConstants.WIDTH_PX_KEY, getWidth());
            data.putInt(UiInterfaceConstants.HEIGHT_PX_KEY, getHeight());
            data.putInt(UiInterfaceConstants.HINT_SPACE_WIDTH_PX_KEY, 0);
            data.putInt(UiInterfaceConstants.HINT_SPACE_HEIGHT_PX_KEY, 0);
            msg.setData(data);
            try {
                mHintServiceInterface.send(msg);
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to send hint tap", e);
            }
        }
    }

    private void getHints() {
        if (mHintServiceInterface != null) {
            try {
                Message m = Message.obtain(null, REQUEST_HINTS_CODE);
                m.replyTo = new Messenger(mUiHintListener);
                mHintServiceInterface.send(m);
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to send message", e);
            }
        }
    }

    private static class UiHintListener extends Handler {
        private HintsContainer mView;

        UiHintListener(HintsContainer v) {
            mView = v;
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case ON_HINTS_RETURNED_CODE:
                    handleHints(msg);
                    break;
                default:
                    Log.e(TAG, "UiPullInterface got unrecognized code: " + msg.what);
                    break;
            }
        }

        private void handleHints(Message msg) {
            Bundle bundle = msg.getData();
            ArrayList<Bundle> hints = bundle.getParcelableArrayList(HINTS_KEY);

            if (hints != null) {
                mView.removeAllViews();

                for (Bundle hint : hints) {
                    HintView h = (HintView) LayoutInflater.from(mView.getContext()).inflate(
                            R.layout.hint, mView, false);
                    h.setHint(hint);
                    h.setOnClickListener((v) -> mView.sendOnHintTap(hint));
                    mView.addView(h);
                }
            }
        }
    }
}
+15 −9
Original line number Diff line number Diff line
@@ -42,9 +42,10 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.util.PendingAnimation;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.views.ScrimView;
import com.android.quickstep.OverviewInteractionState;
import com.android.quickstep.hints.HintsContainer;
import com.android.quickstep.hints.ChipsContainer;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.ClipAnimationHelper.TransformParams;
import com.android.quickstep.util.LayoutUtils;
@@ -77,7 +78,7 @@ public class LauncherRecentsView extends RecentsView<Launcher> {
    private float mTranslationYFactor;

    private final TransformParams mTransformParams = new TransformParams();
    private HintsContainer mHintsContainer;
    private ChipsContainer mChipsContainer;

    public LauncherRecentsView(Context context) {
        this(context, null);
@@ -111,8 +112,9 @@ public class LauncherRecentsView extends RecentsView<Launcher> {
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mHintsContainer = mActivity.findViewById(R.id.hints);
        mHintsContainer.setPadding(0, 0, 0, mActivity.getDeviceProfile().chipHintBottomMarginPx);
        mChipsContainer = mActivity.findViewById(R.id.hints);
        BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) mChipsContainer.getLayoutParams();
        params.bottomMargin = mActivity.getDeviceProfile().chipHintBottomMarginPx;
    }

    public void setTranslationYFactor(float translationFactor) {
@@ -131,11 +133,15 @@ public class LauncherRecentsView extends RecentsView<Launcher> {
    }

    public void setHintVisibility(float v) {
        if (mHintsContainer != null && ENABLE_HINTS_IN_OVERVIEW.get()) {
            mHintsContainer.setHintVisibility(v);
        if (mChipsContainer != null && ENABLE_HINTS_IN_OVERVIEW.get()) {
            mChipsContainer.setHintVisibility(v);
        }
    }

    public ChipsContainer getChipsContainer() {
        return mChipsContainer;
    }

    @Override
    public void draw(Canvas canvas) {
        maybeDrawEmptyMessage(canvas);
@@ -192,7 +198,7 @@ public class LauncherRecentsView extends RecentsView<Launcher> {

        if (ENABLE_HINTS_IN_OVERVIEW.get()) {
            anim.anim.play(ObjectAnimator.ofFloat(
                    mHintsContainer, HintsContainer.HINT_VISIBILITY, 0));
                    mChipsContainer, ChipsContainer.HINT_VISIBILITY, 0));
        }

        return anim;
@@ -206,10 +212,10 @@ public class LauncherRecentsView extends RecentsView<Launcher> {

        if (ENABLE_HINTS_IN_OVERVIEW.get()) {
            anim.anim.play(ObjectAnimator.ofFloat(
                    mHintsContainer, HintsContainer.HINT_VISIBILITY, 0));
                    mChipsContainer, ChipsContainer.HINT_VISIBILITY, 0));
            anim.addEndListener(onEndListener -> {
                if (!onEndListener.isSuccess) {
                    mHintsContainer.setHintVisibility(1);
                    mChipsContainer.setHintVisibility(1);
                }
            });
        }