diff options
-rw-r--r-- | java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java | 9 | ||||
-rw-r--r-- | java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java (renamed from java/com/android/dialer/voicemail/listui/NewVoicemailCallLogAdapter.java) | 29 | ||||
-rw-r--r-- | java/com/android/dialer/voicemail/listui/NewVoicemailCallLogViewHolder.java | 50 | ||||
-rw-r--r-- | java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java | 53 | ||||
-rw-r--r-- | java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java | 60 | ||||
-rw-r--r-- | java/com/android/dialer/voicemail/listui/VoicemailCursorLoader.java | 91 | ||||
-rw-r--r-- | java/com/android/dialer/voicemail/listui/VoicemailEntryText.java | 42 | ||||
-rw-r--r-- | java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_call_log_entry.xml | 2 | ||||
-rw-r--r-- | java/com/android/dialer/voicemail/listui/res/values/strings.xml | 20 | ||||
-rw-r--r-- | java/com/android/dialer/voicemail/model/VoicemailEntry.java | 89 |
10 files changed, 353 insertions, 92 deletions
diff --git a/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java b/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java index a5f1425f8..589fe6384 100644 --- a/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java +++ b/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java @@ -60,6 +60,7 @@ class AnnotatedCallLogDatabaseHelper extends SQLiteOpenHelper { .toString(); /** Deletes all but the first maxRows rows (by timestamp) to keep the table a manageable size. */ + // TODO(zachh): Prevent voicemails from being garbage collected. private static final String CREATE_TRIGGER_SQL = "create trigger delete_old_rows after insert on " + AnnotatedCallLog.TABLE @@ -79,12 +80,20 @@ class AnnotatedCallLogDatabaseHelper extends SQLiteOpenHelper { + AnnotatedCallLog.TABLE + " )); end;"; + private static final String CREATE_INDEX_ON_CALL_TYPE_SQL = + "create index call_type_index on " + + AnnotatedCallLog.TABLE + + " (" + + AnnotatedCallLog.CALL_TYPE + + ");"; + @Override public void onCreate(SQLiteDatabase db) { LogUtil.enterBlock("AnnotatedCallLogDatabaseHelper.onCreate"); long startTime = System.currentTimeMillis(); db.execSQL(CREATE_TABLE_SQL); db.execSQL(String.format(Locale.US, CREATE_TRIGGER_SQL, maxRows, maxRows)); + db.execSQL(CREATE_INDEX_ON_CALL_TYPE_SQL); // TODO(zachh): Consider logging impression. LogUtil.i( "AnnotatedCallLogDatabaseHelper.onCreate", diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailCallLogAdapter.java b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java index b40c8630e..71178ceba 100644 --- a/java/com/android/dialer/voicemail/listui/NewVoicemailCallLogAdapter.java +++ b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java @@ -15,41 +15,40 @@ */ package com.android.dialer.voicemail.listui; +import android.database.Cursor; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.android.dialer.common.LogUtil; -import com.android.dialer.voicemail.datasources.VoicemailData; -import java.util.List; /** {@link RecyclerView.Adapter} for the new voicemail call log fragment. */ -final class NewVoicemailCallLogAdapter extends RecyclerView.Adapter<NewVoicemailCallLogViewHolder> { +final class NewVoicemailAdapter extends RecyclerView.Adapter<NewVoicemailViewHolder> { - private final List<VoicemailData> voicemailData; + private final Cursor cursor; - NewVoicemailCallLogAdapter(List<VoicemailData> dataSet) { - voicemailData = dataSet; + /** @param cursor whose projection is {@link VoicemailCursorLoader.VOICEMAIL_COLUMNS} */ + NewVoicemailAdapter(Cursor cursor) { + this.cursor = cursor; } @Override - public NewVoicemailCallLogViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { - + public NewVoicemailViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext()); - View v = inflater.inflate(R.layout.new_voicemail_call_log_entry, viewGroup, false); - NewVoicemailCallLogViewHolder newVoicemailCallLogViewHolder = - new NewVoicemailCallLogViewHolder(v); - return newVoicemailCallLogViewHolder; + View view = inflater.inflate(R.layout.new_voicemail_call_log_entry, viewGroup, false); + NewVoicemailViewHolder newVoicemailViewHolder = new NewVoicemailViewHolder(view); + return newVoicemailViewHolder; } @Override - public void onBindViewHolder(NewVoicemailCallLogViewHolder viewHolder, int position) { + public void onBindViewHolder(NewVoicemailViewHolder viewHolder, int position) { LogUtil.i("onBindViewHolder", "position" + position); - viewHolder.bind(voicemailData.get(position)); + cursor.moveToPosition(position); + viewHolder.bind(cursor); } @Override public int getItemCount() { - return voicemailData.size(); + return cursor.getCount(); } } diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailCallLogViewHolder.java b/java/com/android/dialer/voicemail/listui/NewVoicemailCallLogViewHolder.java deleted file mode 100644 index 9ec768464..000000000 --- a/java/com/android/dialer/voicemail/listui/NewVoicemailCallLogViewHolder.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 - */ -package com.android.dialer.voicemail.listui; - -import android.support.v7.widget.RecyclerView; -import android.view.View; -import android.widget.TextView; -import com.android.dialer.voicemail.datasources.VoicemailData; - -/** {@link RecyclerView.ViewHolder} for the new voicemail call log. */ -final class NewVoicemailCallLogViewHolder extends RecyclerView.ViewHolder { - - private final TextView primaryTextView; - private final TextView secondaryTextView; - private final TextView transcriptionTextView; - - NewVoicemailCallLogViewHolder(View view) { - super(view); - primaryTextView = (TextView) view.findViewById(R.id.primary_text); - secondaryTextView = (TextView) view.findViewById(R.id.secondary_text); - transcriptionTextView = (TextView) view.findViewById(R.id.transcription_text); - } - - void bind(VoicemailData voicemailData) { - primaryTextView.setText(voicemailData.name()); - secondaryTextView.setText(getVoicemailLocationDateAndDuration(voicemailData)); - transcriptionTextView.setText(voicemailData.transcription()); - } - - private String getVoicemailLocationDateAndDuration(VoicemailData voicemailData) { - return voicemailData.location() - + " · " - + voicemailData.date() - + " · " - + voicemailData.duration(); - } -} diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java index 3629b7551..1912e1e3f 100644 --- a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java +++ b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java @@ -16,49 +16,50 @@ package com.android.dialer.voicemail.listui; +import android.database.Cursor; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager.LoaderCallbacks; +import android.support.v4.content.Loader; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.android.dialer.common.LogUtil; -import com.android.dialer.voicemail.datasources.VoicemailData; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; /** Fragment for Dialer Voicemail Tab. */ -public final class NewVoicemailFragment extends Fragment { +public final class NewVoicemailFragment extends Fragment implements LoaderCallbacks<Cursor> { + + private RecyclerView recyclerView; + @Nullable @Override public View onCreateView( LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.new_voicemail_call_log_fragment, container, false); - RecyclerView recyclerView = - (RecyclerView) view.findViewById(R.id.new_voicemail_call_log_recycler_view); - recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + recyclerView = view.findViewById(R.id.new_voicemail_call_log_recycler_view); + getLoaderManager().restartLoader(0, null, this); + return view; + } - // TODO(uabdullah): To be removed once we hook up the UI to the voicemail backend - List<VoicemailData> voicemailData = new ArrayList<>(); - Random rand = new Random(); - for (int i = 0; i < 50; i++) { - VoicemailData mocked = - VoicemailData.builder() - .setName("Fatima Abdullah " + i) - .setLocation("San Francisco, CA") - .setDate("March " + (rand.nextInt(30) + 1)) - .setDuration("00:" + (rand.nextInt(50) + 10)) - .setTranscription( - "This is a transcription text message that literally means nothing.") - .build(); - voicemailData.add(mocked); - } + @Override + public Loader<Cursor> onCreateLoader(int id, Bundle args) { + LogUtil.enterBlock("NewVoicemailFragment.onCreateLoader"); + return new VoicemailCursorLoader(getContext()); + } - LogUtil.i("onCreateView", "size of input:" + voicemailData.size()); - recyclerView.setAdapter(new NewVoicemailCallLogAdapter(voicemailData)); - return view; + @Override + public void onLoadFinished(Loader<Cursor> loader, Cursor data) { + LogUtil.i("NewVoicemailFragment.onCreateLoader", "cursor size is %d", data.getCount()); + recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + recyclerView.setAdapter(new NewVoicemailAdapter(data)); + } + + @Override + public void onLoaderReset(Loader<Cursor> loader) { + LogUtil.enterBlock("NewVoicemailFragment.onLoaderReset"); + recyclerView.setAdapter(null); } } diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java new file mode 100644 index 000000000..daa24c86c --- /dev/null +++ b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java @@ -0,0 +1,60 @@ +/* + * 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 + */ +package com.android.dialer.voicemail.listui; + +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.QuickContactBadge; +import android.widget.TextView; +import com.android.dialer.contactphoto.ContactPhotoManager; +import com.android.dialer.lettertile.LetterTileDrawable; +import com.android.dialer.voicemail.model.VoicemailEntry; + +/** {@link RecyclerView.ViewHolder} for the new voicemail tab. */ +final class NewVoicemailViewHolder extends RecyclerView.ViewHolder { + + private final Context context; + private final TextView primaryTextView; + private final QuickContactBadge quickContactBadge; + + NewVoicemailViewHolder(View view) { + super(view); + this.context = view.getContext(); + primaryTextView = (TextView) view.findViewById(R.id.primary_text); + quickContactBadge = view.findViewById(R.id.quick_contact_photo); + } + + void bind(Cursor cursor) { + VoicemailEntry voicemailEntry = VoicemailCursorLoader.toVoicemailEntry(cursor); + primaryTextView.setText(VoicemailEntryText.buildPrimaryVoicemailText(context, voicemailEntry)); + setPhoto(voicemailEntry); + } + + // TODO(uabdullah): Consider/Implement TYPE (e.g Spam, TYPE_VOICEMAIL) + private void setPhoto(VoicemailEntry voicemailEntry) { + ContactPhotoManager.getInstance(context) + .loadDialerThumbnailOrPhoto( + quickContactBadge, + voicemailEntry.lookupUri() == null ? null : Uri.parse(voicemailEntry.lookupUri()), + voicemailEntry.photoId(), + voicemailEntry.photoUri() == null ? null : Uri.parse(voicemailEntry.photoUri()), + voicemailEntry.name(), + LetterTileDrawable.TYPE_DEFAULT); + } +} diff --git a/java/com/android/dialer/voicemail/listui/VoicemailCursorLoader.java b/java/com/android/dialer/voicemail/listui/VoicemailCursorLoader.java new file mode 100644 index 000000000..5a4176542 --- /dev/null +++ b/java/com/android/dialer/voicemail/listui/VoicemailCursorLoader.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +package com.android.dialer.voicemail.listui; + +import android.content.Context; +import android.database.Cursor; +import android.provider.CallLog.Calls; +import android.support.v4.content.CursorLoader; +import com.android.dialer.DialerPhoneNumber; +import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.AnnotatedCallLog; +import com.android.dialer.voicemail.model.VoicemailEntry; +import com.google.protobuf.InvalidProtocolBufferException; + +/** CursorLoader for the annotated call log (voicemails only). */ +final class VoicemailCursorLoader extends CursorLoader { + + // When adding columns be sure to update {@link #VoicemailCursorLoader.toVoicemailEntry}. + public static final String[] VOICEMAIL_COLUMNS = + new String[] { + AnnotatedCallLog._ID, + AnnotatedCallLog.TIMESTAMP, + AnnotatedCallLog.NAME, + AnnotatedCallLog.NUMBER, + AnnotatedCallLog.FORMATTED_NUMBER, + AnnotatedCallLog.PHOTO_URI, + AnnotatedCallLog.PHOTO_ID, + AnnotatedCallLog.LOOKUP_URI, + AnnotatedCallLog.GEOCODED_LOCATION, + AnnotatedCallLog.CALL_TYPE + }; + + // Indexes for VOICEMAIL_COLUMNS + private static final int ID = 0; + private static final int TIMESTAMP = 1; + private static final int NAME = 2; + private static final int NUMBER = 3; + private static final int FORMATTED_NUMBER = 4; + private static final int PHOTO_URI = 5; + private static final int PHOTO_ID = 6; + private static final int LOOKUP_URI = 7; + private static final int GEOCODED_LOCATION = 8; + private static final int CALL_TYPE = 9; + + // TODO(zachh): Optimize indexes + VoicemailCursorLoader(Context context) { + super( + context, + AnnotatedCallLog.CONTENT_URI, + VOICEMAIL_COLUMNS, + AnnotatedCallLog.CALL_TYPE + " = ?", + new String[] {Integer.toString(Calls.VOICEMAIL_TYPE)}, + AnnotatedCallLog.TIMESTAMP + " DESC"); + } + + /** Creates a new {@link VoicemailEntry} from the provided cursor using the current position. */ + static VoicemailEntry toVoicemailEntry(Cursor cursor) { + DialerPhoneNumber number; + try { + number = DialerPhoneNumber.parseFrom(cursor.getBlob(NUMBER)); + } catch (InvalidProtocolBufferException e) { + throw new IllegalStateException("Couldn't parse DialerPhoneNumber bytes"); + } + + return VoicemailEntry.builder() + .setId(cursor.getInt(ID)) + .setTimestamp(cursor.getLong(TIMESTAMP)) + .setName(cursor.getString(NAME)) + .setNumber(number) + .setFormattedNumber(cursor.getString(FORMATTED_NUMBER)) + .setPhotoUri(cursor.getString(PHOTO_URI)) + .setPhotoId(cursor.getLong(PHOTO_ID)) + .setLookupUri(cursor.getString(LOOKUP_URI)) + .setGeocodedLocation(cursor.getString(GEOCODED_LOCATION)) + .setCallType(cursor.getInt(CALL_TYPE)) + .build(); + } +} diff --git a/java/com/android/dialer/voicemail/listui/VoicemailEntryText.java b/java/com/android/dialer/voicemail/listui/VoicemailEntryText.java new file mode 100644 index 000000000..cf2fef253 --- /dev/null +++ b/java/com/android/dialer/voicemail/listui/VoicemailEntryText.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package com.android.dialer.voicemail.listui; + +import android.content.Context; +import android.text.TextUtils; +import com.android.dialer.voicemail.model.VoicemailEntry; + +/** + * Computes the primary text for voicemail entries. + * + * <p>These text values are shown in the voicemail tab. + */ +public class VoicemailEntryText { + + public static String buildPrimaryVoicemailText(Context context, VoicemailEntry data) { + StringBuilder primaryText = new StringBuilder(); + if (!TextUtils.isEmpty(data.name())) { + primaryText.append(data.name()); + } else if (!TextUtils.isEmpty(data.formattedNumber())) { + primaryText.append(data.formattedNumber()); + } else { + // TODO(uabdullah): Handle CallLog.Calls.PRESENTATION_*, including Verizon restricted numbers. + primaryText.append(context.getText(R.string.voicemail_entry_unknown)); + } + return primaryText.toString(); + } +} diff --git a/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_call_log_entry.xml b/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_call_log_entry.xml index 01c0ee12e..82ccf88d2 100644 --- a/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_call_log_entry.xml +++ b/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_call_log_entry.xml @@ -31,7 +31,6 @@ android:layout_height="@dimen/call_log_entry_photo_size" android:layout_centerVertical="true" android:padding="@dimen/call_log_entry_photo_padding" - android:background="@color/dialer_secondary_color" android:focusable="true"/> <LinearLayout @@ -42,6 +41,7 @@ android:layout_toStartOf="@+id/menu_button" android:orientation="vertical"> + <!--TODO(uabdullah): Resolve text clipping on top of primary text --> <TextView android:id="@+id/primary_text" style="@style/PrimaryText" diff --git a/java/com/android/dialer/voicemail/listui/res/values/strings.xml b/java/com/android/dialer/voicemail/listui/res/values/strings.xml new file mode 100644 index 000000000..39c368a5a --- /dev/null +++ b/java/com/android/dialer/voicemail/listui/res/values/strings.xml @@ -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 + --> +<resources> + <!-- String used to display voicemails from unknown numbers in the voicemail tab. [CHAR LIMIT=30] --> + <string name="voicemail_entry_unknown">Unknown</string> +</resources>
\ No newline at end of file diff --git a/java/com/android/dialer/voicemail/model/VoicemailEntry.java b/java/com/android/dialer/voicemail/model/VoicemailEntry.java new file mode 100644 index 000000000..00e1757dc --- /dev/null +++ b/java/com/android/dialer/voicemail/model/VoicemailEntry.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package com.android.dialer.voicemail.model; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.android.dialer.DialerPhoneNumber; +import com.google.auto.value.AutoValue; + +/** Data class containing the contents of a voicemail entry from the AnnotatedCallLog. */ +@AutoValue +public abstract class VoicemailEntry { + + public static Builder builder() { + return new AutoValue_VoicemailEntry.Builder() + .setId(0) + .setTimestamp(0) + .setNumber(DialerPhoneNumber.getDefaultInstance()) + .setPhotoId(0) + .setCallType(0); + } + + public abstract int id(); + + public abstract long timestamp(); + + @NonNull + public abstract DialerPhoneNumber number(); + + @Nullable + public abstract String name(); + + @Nullable + public abstract String formattedNumber(); + + @Nullable + public abstract String photoUri(); + + public abstract long photoId(); + + @Nullable + public abstract String lookupUri(); + + @Nullable + public abstract String geocodedLocation(); + + public abstract int callType(); + + /** Builder for {@link VoicemailEntry}. */ + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder setId(int id); + + public abstract Builder setTimestamp(long timestamp); + + public abstract Builder setNumber(@NonNull DialerPhoneNumber number); + + public abstract Builder setName(@Nullable String name); + + public abstract Builder setFormattedNumber(@Nullable String formattedNumber); + + public abstract Builder setPhotoUri(@Nullable String photoUri); + + public abstract Builder setPhotoId(long photoId); + + public abstract Builder setLookupUri(@Nullable String lookupUri); + + public abstract Builder setGeocodedLocation(@Nullable String geocodedLocation); + + public abstract Builder setCallType(int callType); + + public abstract VoicemailEntry build(); + } +} |