13d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer/*
23d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * Copyright (C) 2015 The Android Open Source Project
33d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer *
43d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * Licensed under the Apache License, Version 2.0 (the "License");
53d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * you may not use this file except in compliance with the License.
63d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * You may obtain a copy of the License at
73d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer *
83d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer *      http://www.apache.org/licenses/LICENSE-2.0
93d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer *
103d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * Unless required by applicable law or agreed to in writing, software
113d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * distributed under the License is distributed on an "AS IS" BASIS,
123d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * See the License for the specific language governing permissions and
143d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * limitations under the License.
153d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer */
163d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerpackage com.android.car.dialer;
173d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
183d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.content.ContentResolver;
193d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.content.Context;
203d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.content.CursorLoader;
2197b319e44253a215dab1e6d626fcdc5f56d3867cAnthony Chenimport android.content.res.Resources;
223d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.database.ContentObserver;
233d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.database.Cursor;
243d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.graphics.Canvas;
2597b319e44253a215dab1e6d626fcdc5f56d3867cAnthony Chenimport android.graphics.Paint;
263d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.net.Uri;
273d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.os.Bundle;
283d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.os.Handler;
293d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.support.annotation.Nullable;
303d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.support.v4.app.Fragment;
313d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.support.v7.widget.RecyclerView;
323d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.util.Log;
333d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.view.LayoutInflater;
343d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.view.View;
353d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.view.ViewGroup;
363d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.widget.LinearLayout;
3717d5ac7d0b429687765e940279726623f5f5f823Anthony Chen
383d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport com.android.car.dialer.telecom.PhoneLoader;
393d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport com.android.car.dialer.telecom.UiCallManager;
409c60bc83bd37ae212e66f2e27b821cebbe7beeb2Rakesh Iyerimport com.android.car.view.PagedListView;
413d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
423d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer/**
433d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * Contains a list of contacts. The call types can be any of the CALL_TYPE_* fields from
443d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * {@link PhoneLoader}.
453d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer */
463d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerpublic class StrequentsFragment extends Fragment {
473d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    private static final String TAG = "Em.StrequentsFrag";
483d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
4917d5ac7d0b429687765e940279726623f5f5f823Anthony Chen    private static final String KEY_MAX_CLICKS = "max_clicks";
5017d5ac7d0b429687765e940279726623f5f5f823Anthony Chen    private static final int DEFAULT_MAX_CLICKS = 6;
513d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
526ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan    private UiCallManager mUiCallManager;
533d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    private StrequentsAdapter mAdapter;
543d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    private CursorLoader mSpeedialCursorLoader;
553d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    private CursorLoader mCallLogCursorLoader;
563d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    private Context mContext;
573d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    private PagedListView mListView;
583d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    private Cursor mStrequentCursor;
593d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    private Cursor mCallLogCursor;
603d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    private boolean mHasLoadedData;
613d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
626ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan    public static StrequentsFragment newInstance(UiCallManager callManager) {
636ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan        StrequentsFragment fragment = new StrequentsFragment();
646ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan        fragment.mUiCallManager = callManager;
656ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan        return fragment;
666ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan    }
676ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan
683d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    @Override
693d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    public void onCreate(@Nullable Bundle savedInstanceState) {
703d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        super.onCreate(savedInstanceState);
713d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        if (Log.isLoggable(TAG, Log.DEBUG)) {
723d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            Log.d(TAG, "onCreate");
733d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
743d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    }
753d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
763d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    @Override
773d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    public View onCreateView(LayoutInflater inflater, ViewGroup container,
783d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            Bundle savedInstanceState) {
793d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        if (Log.isLoggable(TAG, Log.DEBUG)) {
803d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            Log.d(TAG, "onCreateView");
813d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
823d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
836f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan        mContext = getContext();
843d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
853d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        View view = inflater.inflate(R.layout.strequents_fragment, container, false);
863d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mListView = (PagedListView) view.findViewById(R.id.list_view);
873d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mListView.getLayoutManager().setOffsetRows(true);
883d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
893d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mSpeedialCursorLoader = PhoneLoader.registerCallObserver(PhoneLoader.CALL_TYPE_SPEED_DIAL,
906f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan            mContext, (loader, cursor) -> {
916f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan                if (Log.isLoggable(TAG, Log.DEBUG)) {
926f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan                    Log.d(TAG, "PhoneLoader: onLoadComplete (CALL_TYPE_SPEED_DIAL)");
936f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan                }
943d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
956f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan                onLoadStrequentCursor(cursor);
963d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
976f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan                if (mContext != null) {
9897b319e44253a215dab1e6d626fcdc5f56d3867cAnthony Chen                    mListView.addItemDecoration(new Decoration(mContext));
996f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan                }
1006f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan            });
1013d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
1023d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        // Get the latest call log from the call logs history.
1033d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mCallLogCursorLoader = PhoneLoader.registerCallObserver(PhoneLoader.CALL_TYPE_ALL, mContext,
1046f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan            (loader, cursor) -> {
1056f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan                if (Log.isLoggable(TAG, Log.DEBUG)) {
1066f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan                    Log.d(TAG, "PhoneLoader: onLoadComplete (CALL_TYPE_ALL)");
1076f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan                }
1086f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan                onLoadCallLogCursor(cursor);
1096f8e1dbe4629b499128dade1e6d83e37147403c4Srinivas Visvanathan            });
1103d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
1113d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        ContentResolver contentResolver = mContext.getContentResolver();
1123d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        contentResolver.registerContentObserver(mSpeedialCursorLoader.getUri(),
1133d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                false, new SpeedDialContentObserver(new Handler()));
1143d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        contentResolver.registerContentObserver(mCallLogCursorLoader.getUri(),
1153d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                false, new CallLogContentObserver(new Handler()));
1163d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
1173d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        // Maximum number of forward acting clicks the user can perform
11817d5ac7d0b429687765e940279726623f5f5f823Anthony Chen        Bundle args = getArguments();
11917d5ac7d0b429687765e940279726623f5f5f823Anthony Chen        int maxClicks = args == null
12017d5ac7d0b429687765e940279726623f5f5f823Anthony Chen                ? DEFAULT_MAX_CLICKS
12117d5ac7d0b429687765e940279726623f5f5f823Anthony Chen                : args.getInt(KEY_MAX_CLICKS, DEFAULT_MAX_CLICKS /* G.maxForwardClicks.get() */);
1223d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        // We want to show one fewer page than max clicks to allow clicking on an item,
1233d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        // but, the first page is "free" since it doesn't take any clicks to show
1243d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        final int maxPages = maxClicks < 0 ? -1 : maxClicks;
1253d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1263d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            Log.v(TAG, "Max clicks: " + maxClicks + ", Max pages: " + maxPages);
1273d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
1283d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
1293d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mListView.setLightMode();
1306ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan        mAdapter = new StrequentsAdapter(mContext, mUiCallManager);
1313d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mAdapter.setStrequentsListener(viewHolder -> {
1323d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            if (Log.isLoggable(TAG, Log.DEBUG)) {
1333d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                Log.d(TAG, "onContactedClicked");
1343d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            }
1353d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
1366ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan            mUiCallManager.safePlaceCall((String) viewHolder.itemView.getTag(), false);
1373d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        });
1383d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mListView.setMaxPages(maxPages);
1393d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mListView.setAdapter(mAdapter);
1403d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
1413d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        if (Log.isLoggable(TAG, Log.DEBUG)) {
1423d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            Log.d(TAG, "setItemAnimator");
1433d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
1443d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
1453d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mListView.getRecyclerView().setItemAnimator(new StrequentsItemAnimator());
1463d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        return view;
1473d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    }
1483d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
1493d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    @Override
1503d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    public void onDestroyView() {
1513d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        super.onDestroyView();
1523d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
1533d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        if (Log.isLoggable(TAG, Log.DEBUG)) {
1543d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            Log.d(TAG, "onDestroyView");
1553d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
1563d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
1573d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mAdapter.setStrequentCursor(null);
1583d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mAdapter.setLastCallCursor(null);
1593d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mCallLogCursorLoader.reset();
1603d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mSpeedialCursorLoader.reset();
1613d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mCallLogCursor = null;
1623d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mStrequentCursor = null;
1633d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mHasLoadedData = false;
1643d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mContext = null;
1653d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    }
1663d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
1673d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    private void loadDataIntoAdapter() {
1683d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        if (Log.isLoggable(TAG, Log.DEBUG)) {
1693d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            Log.d(TAG, "loadDataIntoAdapter");
1703d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
1713d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
1723d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mHasLoadedData = true;
1733d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mAdapter.setLastCallCursor(mCallLogCursor);
1743d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mAdapter.setStrequentCursor(mStrequentCursor);
1753d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    }
1763d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
1773d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    private void onLoadStrequentCursor(Cursor cursor) {
1783d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        if (Log.isLoggable(TAG, Log.DEBUG)) {
1793d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            Log.d(TAG, "onLoadStrequentCursor");
1803d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
1813d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
1823d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        if (cursor == null) {
1833d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            throw new IllegalArgumentException(
1843d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                    "cursor was null in on speed dial fetched");
1853d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
1863d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
1873d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mStrequentCursor = cursor;
1883d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        if (mCallLogCursor != null) {
1893d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            if (mHasLoadedData) {
1903d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                mAdapter.setStrequentCursor(cursor);
1913d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            } else {
1923d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                loadDataIntoAdapter();
1933d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            }
1943d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
1953d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    }
1963d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
1973d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    private void onLoadCallLogCursor(Cursor cursor) {
1983d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        if (cursor == null) {
1993d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            throw new IllegalArgumentException(
2003d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                    "cursor was null in on calls fetched");
2013d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
2023d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
2033d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        mCallLogCursor = cursor;
2043d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        if (mStrequentCursor != null) {
2053d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            if (mHasLoadedData) {
2063d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                mAdapter.setLastCallCursor(cursor);
2073d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            } else {
2083d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                loadDataIntoAdapter();
2093d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            }
2103d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
2113d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    }
2123d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
2133d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    /**
2143d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer     * A {@link ContentResolver} that is responsible for reloading the user's starred and frequent
2153d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer     * contacts.
2163d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer     */
2173d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    private class SpeedDialContentObserver extends ContentObserver {
2183d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        public SpeedDialContentObserver(Handler handler) {
2193d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            super(handler);
2203d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
2213d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
2223d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        @Override
2233d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        public void onChange(boolean selfChange) {
2243d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            onChange(selfChange, null);
2253d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
2263d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
2273d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        @Override
2283d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        public void onChange(boolean selfChange, Uri uri) {
2293d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            if (Log.isLoggable(TAG, Log.DEBUG)) {
2303d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                Log.d(TAG, "SpeedDialContentObserver onChange() called. Reloading strequents.");
2313d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            }
2323d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            mSpeedialCursorLoader.startLoading();
2333d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
2343d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    }
2353d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
2363d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    /**
2373d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer     * A {@link ContentResolver} that is responsible for reloading the user's recent calls.
2383d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer     */
2393d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    private class CallLogContentObserver extends ContentObserver {
2403d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        public CallLogContentObserver(Handler handler) {
2413d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            super(handler);
2423d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
2433d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
2443d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        @Override
2453d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        public void onChange(boolean selfChange) {
2463d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            onChange(selfChange, null);
2473d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
2483d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
2493d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        @Override
2503d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        public void onChange(boolean selfChange, Uri uri) {
2513d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            if (Log.isLoggable(TAG, Log.DEBUG)) {
2523d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                Log.d(TAG, "CallLogContentObserver onChange() called. Reloading call log.");
2533d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            }
2543d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            mCallLogCursorLoader.startLoading();
2553d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
2563d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    }
2573d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
2583d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    /**
25997b319e44253a215dab1e6d626fcdc5f56d3867cAnthony Chen     * Decoration for the speed dial cards. This ItemDecoration will not show a divider between
26097b319e44253a215dab1e6d626fcdc5f56d3867cAnthony Chen     * the dialpad item and the first speed dial item and the divider is offset but a couple of
26197b319e44253a215dab1e6d626fcdc5f56d3867cAnthony Chen     * pixels to offset the fact that the cards overlap.
2623d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer     */
26397b319e44253a215dab1e6d626fcdc5f56d3867cAnthony Chen    private static class Decoration extends RecyclerView.ItemDecoration {
26497b319e44253a215dab1e6d626fcdc5f56d3867cAnthony Chen        private final Paint mPaint;
2653d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        private final int mPaintAlpha;
26697b319e44253a215dab1e6d626fcdc5f56d3867cAnthony Chen        private final int mDividerHeight;
2673d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
2683d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        public Decoration(Context context) {
26997b319e44253a215dab1e6d626fcdc5f56d3867cAnthony Chen            Resources res = context.getResources();
27097b319e44253a215dab1e6d626fcdc5f56d3867cAnthony Chen            mPaint = new Paint();
27197b319e44253a215dab1e6d626fcdc5f56d3867cAnthony Chen            mPaint.setColor(res.getColor(R.color.car_list_divider));
27297b319e44253a215dab1e6d626fcdc5f56d3867cAnthony Chen            mDividerHeight = res.getDimensionPixelSize(R.dimen.car_divider_height);
2733d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            mPaintAlpha = mPaint.getAlpha();
2743d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
2753d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
2763d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        @Override
2773d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
2783d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            StrequentsAdapter adapter = (StrequentsAdapter) parent.getAdapter();
2793d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
2803d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            if (adapter.getItemCount() <= 0) {
2813d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                return;
2823d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            }
2833d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
2843d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            final int childCount = parent.getChildCount();
2853d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
2863d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            // Don't draw decoration line on last item of the list.
2873d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            for (int i = 0; i < childCount - 1; i++) {
2883d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                final View child = parent.getChildAt(i);
2893d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
2903d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                // If the child is focused then the decoration will look bad with the focus
2913d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                // highlight so don't draw it.
2923d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                if (child.isFocused()) {
2933d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                    continue;
2943d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                }
2953d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
2963d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                // The left edge of the divider should align with the left edge of text_container.
29797b319e44253a215dab1e6d626fcdc5f56d3867cAnthony Chen                LinearLayout container = child.findViewById(R.id.container);
2983d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                View textContainer = child.findViewById(R.id.text_container);
2993d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                View card = child.findViewById(R.id.call_log_card);
3003d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
3013d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                int left = textContainer.getLeft() + container.getLeft() + card.getLeft();
3023d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                int right = left + textContainer.getWidth();
3033d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
3043d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
3053d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                int bottom = child.getBottom() + lp.bottomMargin
30617d5ac7d0b429687765e940279726623f5f5f823Anthony Chen                        + Math.round(child.getTranslationY());
3073d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                int top = bottom - mDividerHeight;
3083d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
3093d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                if (top >= c.getHeight() || top < 0) {
3103d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                    break;
3113d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                }
3123d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer
3133d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                mPaint.setAlpha(Math.round(container.getAlpha() * mPaintAlpha));
3143d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer                c.drawRect(left, top, right, bottom, mPaint);
3153d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer            }
3163d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer        }
3173d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer    }
3183d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer}
319