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

Commit 3a18654b authored by Yorke Lee's avatar Yorke Lee
Browse files

Animation for smart dialing suggestions

Suggestions now appear with a fade in and slide up animation.
Suggestions vanish with a fade out and slide down animation.
If a suggestion is moved into the middle, it slides to the left/right
as appropriate.

Change the layout containing suggestions to a LinearLayout, in order to
better support animations.

Renamed SmartDialAdapter to SmartDialController, and also refactored
it to handle entries for a LinearLayout instead of a GridView, as well
as adding animation support and view management.

Use null object pattern in SmartDialEntry to better handle null entries.

Start displaying suggestions on the first digit entered.

Bug 8840240

Change-Id: If4e16006c0b36d2244434e0b2d8f3d3b997b0ad2
parent dbb6c6fc
Loading
Loading
Loading
Loading
+21 −9
Original line number Diff line number Diff line
@@ -57,17 +57,29 @@
            android:src="@drawable/ic_dial_action_delete" />
    </LinearLayout>

    <!-- Smard dial suggestion section -->
    <GridView
        android:id="@+id/dialpad_smartdial_list"
    <!-- Smart dial suggestion section.
         sp is used here for this layout instead of dp in order for it to resize as
         appropriate when the font size increases. This is a one-time exception that is
         ok in this case because there is space for the suggestion strip to expand. -->
    <RelativeLayout
        android:id="@+id/dialpad_smartdial_container"
        android:layout_width="match_parent"
        android:layout_height="50sp"
        android:columnWidth="0dp"
        android:numColumns="3"
        android:stretchMode="columnWidth"
        android:gravity="center"
        android:layout_marginTop="@dimen/dialpad_vertical_margin"
        android:background="@drawable/dialpad_background"/>
        android:layout_marginTop="@dimen/dialpad_vertical_margin">
        <View
            android:id="@+id/dialpad_smartdial_list_background"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/dialpad_background">
        </View>
        <LinearLayout
            android:id="@+id/dialpad_smartdial_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            android:gravity="center">
        </LinearLayout>
    </RelativeLayout>

    <!-- Keypad section -->
    <include layout="@layout/dialpad" />
+8 −4
Original line number Diff line number Diff line
@@ -16,15 +16,19 @@
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="46sp">
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="match_parent"
    android:layout_marginTop="2dp"
    android:layout_marginBottom="2dp"
    android:background="?android:attr/selectableItemBackground">

    <com.android.dialer.dialpad.SmartDialTextView
        android:id="@+id/contact_name"
        android:layout_width="match_parent"
        android:layout_height="28sp"
        android:padding="@dimen/smartdial_suggestions_padding"
        android:textColor="@color/smartdial_primary_text_color"
        android:textColor="@color/smartdial_name_primary_text_color"
        android:textSize="16sp"
        android:singleLine="true"
        android:ellipsize="none"
@@ -34,7 +38,7 @@
        android:id="@+id/contact_number"
        android:layout_width="match_parent"
        android:layout_height="16sp"
        android:textColor="@color/dialtacts_secondary_text_color"
        android:textColor="@color/smartdial_number_primary_text_color"
        android:textSize="13sp"
        android:gravity="center"
    />
+4 −3
Original line number Diff line number Diff line
@@ -18,9 +18,10 @@

    <!-- Secondary text color in the Phone app -->
    <color name="dialtacts_secondary_text_color">#888888</color>
    <color name="smartdial_confidence_drawable_color">#39caff</color>
    <color name="smartdial_primary_text_color">#39caff</color>
    <color name="smartdial_highlighted_text_color">#ffffff</color>
    <color name="smartdial_name_primary_text_color">#0099cc</color>
    <color name="smartdial_name_highlighted_text_color">#39c9ff</color>
    <color name="smartdial_number_primary_text_color">#bbbbbb</color>
    <color name="smartdial_number_highlighted_text_color">#ffffff</color>

    <!-- Color of the text describing an unconsumed missed call. -->
    <color name="call_log_missed_call_highlight_color">#FF0000</color>
+17 −16
Original line number Diff line number Diff line
@@ -67,8 +67,10 @@ import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.android.contacts.common.CallUtil;
@@ -147,13 +149,12 @@ public class DialpadFragment extends Fragment
    private DialpadChooserAdapter mDialpadChooserAdapter;

    /** Will be set only if the view has the smart dialing section. */
    private AbsListView mSmartDialList;
    private RelativeLayout mSmartDialContainer;

    /**
     * Adapter for {@link #mSmartDialList}.
     * Will be set only if the view has the smart dialing section.
     */
    private SmartDialAdapter mSmartDialAdapter;
    private SmartDialController mSmartDialAdapter;

    private SmartDialCache mSmartDialCache;
    /**
@@ -368,12 +369,12 @@ public class DialpadFragment extends Fragment
        mDialpadChooser.setOnItemClickListener(this);

        // Smart dial
        mSmartDialList = (AbsListView) fragmentView.findViewById(R.id.dialpad_smartdial_list);
        if (mSmartDialList != null) {
            mSmartDialAdapter = new SmartDialAdapter(getActivity());
            mSmartDialList.setAdapter(mSmartDialAdapter);
            mSmartDialList.setOnItemClickListener(new OnSmartDialItemClick());
            mSmartDialList.setOnItemLongClickListener(new OnSmartDialLongClick());
        mSmartDialContainer = (RelativeLayout) fragmentView.findViewById(
                R.id.dialpad_smartdial_container);

        if (mSmartDialContainer != null) {
            mSmartDialAdapter = new SmartDialController(getActivity(), mSmartDialContainer,
                    new OnSmartDialShortClick(), new OnSmartDialLongClick());
        }
        return fragmentView;
    }
@@ -1697,7 +1698,7 @@ public class DialpadFragment extends Fragment
        }
        mLastDigitsForSmartDial = digits;

        if (digits.length() < 2) {
        if (digits.length() < 1) {
            mSmartDialAdapter.clear();
        } else {
            final SmartDialLoaderTask task = new SmartDialLoaderTask(this, digits, mSmartDialCache);
@@ -1716,7 +1717,7 @@ public class DialpadFragment extends Fragment
    private void initializeSmartDialingState() {
        // Handle smart dialing related state
        if (mSmartDialEnabled) {
            mSmartDialList.setVisibility(View.VISIBLE);
            mSmartDialContainer.setVisibility(View.VISIBLE);
            mSmartDialCache = SmartDialCache.getInstance(getActivity(),
                    mContactsPrefs.getDisplayOrder());
            // Don't force recache if this is the first time onResume is being called, since
@@ -1730,14 +1731,14 @@ public class DialpadFragment extends Fragment
                mSmartDialCache.cacheIfNeeded(true);
            }
        } else {
            mSmartDialList.setVisibility(View.GONE);
            mSmartDialContainer.setVisibility(View.GONE);
            mSmartDialCache = null;
        }
    }

    private class OnSmartDialLongClick implements AdapterView.OnItemLongClickListener {
    private class OnSmartDialLongClick implements View.OnLongClickListener {
        @Override
        public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
        public boolean onLongClick(View view) {
            final SmartDialEntry entry = (SmartDialEntry) view.getTag();
            if (entry == null) return false; // just in case.
            mClearDigitsOnStop = true;
@@ -1749,9 +1750,9 @@ public class DialpadFragment extends Fragment
        }
    }

    private class OnSmartDialItemClick implements AdapterView.OnItemClickListener {
    private class OnSmartDialShortClick implements View.OnClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        public void onClick(View view) {
            final SmartDialEntry entry = (SmartDialEntry) view.getTag();
            if (entry == null) return; // just in case.
            // Dial the displayed phone number immediately
+0 −166
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 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.dialer.dialpad;

import android.content.Context;
import android.content.res.Resources;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;

import com.android.dialer.R;
import com.google.common.collect.Lists;

import java.util.List;

public class SmartDialAdapter extends BaseAdapter {
    public static final String LOG_TAG = "SmartDial";
    private final LayoutInflater mInflater;

    private List<SmartDialEntry> mEntries;

    private final int mHighlightedTextColor;

    public SmartDialAdapter(Context context) {
        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        final Resources res = context.getResources();
        mHighlightedTextColor = res.getColor(R.color.smartdial_highlighted_text_color);
        clear();
    }

    /** Remove all entries. */
    public void clear() {
        mEntries = Lists.newArrayList();
        notifyDataSetChanged();
    }

    /** Set entries. */
    public void setEntries(List<SmartDialEntry> entries) {
        if (entries == null) throw new IllegalArgumentException();
        mEntries = entries;

        if (mEntries.size() <= 1) {
            // add a null entry to push the single entry into the middle
            mEntries.add(0, null);
        } else if (mEntries.size() >= 2){
            // swap the 1st and 2nd entries so that the highest confidence match goes into the
            // middle
            final SmartDialEntry temp = mEntries.get(0);
            mEntries.set(0, mEntries.get(1));
            mEntries.set(1, temp);
        }

        notifyDataSetChanged();
    }

    @Override
    public boolean isEnabled(int position) {
        return !(mEntries.get(position) == null);
    }

    @Override
    public boolean areAllItemsEnabled() {
        return false;
    }

    @Override
    public int getCount() {
        return mEntries.size();
    }

    @Override
    public Object getItem(int position) {
        return mEntries.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position; // Just use the position as the ID, so it's not stable.
    }

    @Override
    public boolean hasStableIds() {
        return false; // Not stable because we just use the position as the ID.
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final LinearLayout view;
        if (convertView == null) {
            view = (LinearLayout) mInflater.inflate(
                    R.layout.dialpad_smartdial_item, parent, false);
        } else {
            view = (LinearLayout) convertView;
        }

        final SmartDialTextView nameView = (SmartDialTextView) view.findViewById(R.id.contact_name);

        final SmartDialTextView numberView = (SmartDialTextView) view.findViewById(
                R.id.contact_number);

        final SmartDialEntry item = mEntries.get(position);

        if (item == null) {
            // Clear the text in case the view was reused.
            nameView.setText("");
            numberView.setText("");
            // Empty view. We use this to force a single entry to be in the middle
            return view;
        }

        // Highlight the display name with the provided match positions
        if (!TextUtils.isEmpty(item.displayName)) {
            final SpannableString displayName = new SpannableString(item.displayName);
            for (final SmartDialMatchPosition p : item.matchPositions) {
                if (p.start < p.end) {
                    if (p.end > displayName.length()) {
                        p.end = displayName.length();
                    }
                    // Create a new ForegroundColorSpan for each section of the name to highlight,
                    // otherwise multiple highlights won't work.
                    displayName.setSpan(new ForegroundColorSpan(mHighlightedTextColor), p.start,
                            p.end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                }
            }
            nameView.setText(displayName);
        }

        // Highlight the phone number with the provided match positions
        if (!TextUtils.isEmpty(item.phoneNumber)) {
            final SmartDialMatchPosition p = item.phoneNumberMatchPosition;
            final SpannableString phoneNumber = new SpannableString(item.phoneNumber);
            if (p != null && p.start < p.end) {
                if (p.end > phoneNumber.length()) {
                    p.end = phoneNumber.length();
                }
                phoneNumber.setSpan(new ForegroundColorSpan(mHighlightedTextColor), p.start, p.end,
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
            numberView.setText(phoneNumber);
        }
        view.setTag(item);

        return view;
    }
}
Loading