Bug 1220928 - Clients and history loading. r=sebastian

MozReview-Commit-ID: 1lCKVQH54C3

--HG--
extra : rebase_source : 2b4b9446e78568bd75e4a827c7454c1958b889cc
This commit is contained in:
Chenxia Liu 2016-02-24 14:27:55 -08:00
parent 923452d82a
commit cb9bba392a
8 changed files with 227 additions and 5 deletions

View File

@ -169,7 +169,7 @@ public class RemoteTabsExpandableListAdapter extends BaseExpandableListAdapter {
// It's OK to access the DB on the main thread here, as we're just
// getting a string.
final GeckoProfile profile = GeckoProfile.get(context);
holder.lastModifiedView.setText(this.getLastSyncedString(context, now, client.lastModified));
holder.lastModifiedView.setText(getLastSyncedString(context, now, client.lastModified));
// These views exists only in some of our group views: they are present
// for the home panel groups and not for the tabs panel groups.
@ -236,7 +236,7 @@ public class RemoteTabsExpandableListAdapter extends BaseExpandableListAdapter {
* @param time to format string for.
* @return string describing time span
*/
public String getLastSyncedString(Context context, long now, long time) {
public static String getLastSyncedString(Context context, long now, long time) {
if (new Date(time).before(EARLIEST_VALID_SYNCED_DATE)) {
return context.getString(R.string.remote_tabs_never_synced);
}

View File

@ -4,8 +4,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.home;
import android.database.Cursor;
import android.support.v7.widget.RecyclerView;
import android.content.Context;
import android.database.Cursor;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -23,11 +25,36 @@ public class CombinedHistoryAdapter extends RecyclerView.Adapter<CombinedHistory
private List<RemoteClient> remoteClients = Collections.emptyList();
private Cursor historyCursor;
private final Context context;
public CombinedHistoryAdapter(Context context) {
super();
this.context = context;
}
public void setClients(List<RemoteClient> clients) {
remoteClients = clients;
notifyDataSetChanged();
}
public void setHistory(Cursor history) {
historyCursor = history;
notifyDataSetChanged();
}
private int transformPosition(ItemType type, int position) {
if (type == ItemType.CLIENT) {
return position;
} else {
return position - (remoteClients == null ? 0 : remoteClients.size());
}
}
@Override
public CombinedHistoryItem onCreateViewHolder(ViewGroup viewGroup, int viewType) {
final LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
final View view;
if (viewType == ItemType.CLIENT.ordinal()) {
view = inflater.inflate(R.layout.home_remote_tabs_group, viewGroup, false);
return new CombinedHistoryItem.ClientItem(view);
@ -51,6 +78,23 @@ public class CombinedHistoryAdapter extends RecyclerView.Adapter<CombinedHistory
}
@Override
public void onBindViewHolder(CombinedHistoryItem viewHolder, int position) {}
public void onBindViewHolder(CombinedHistoryItem viewHolder, int position) {
final ItemType itemType = ItemType.values()[getItemViewType(position)];
final int localPosition = transformPosition(itemType, position);
switch (itemType) {
case CLIENT:
final CombinedHistoryItem.ClientItem clientItem = (CombinedHistoryItem.ClientItem) viewHolder;
final RemoteClient client = remoteClients.get(localPosition);
clientItem.bind(client, context);
break;
case HISTORY:
if (historyCursor == null || !historyCursor.moveToPosition(localPosition)) {
throw new IllegalStateException("Couldn't move cursor to position " + localPosition);
}
((CombinedHistoryItem.HistoryItem) viewHolder).bind(historyCursor);
break;
}
}
}

View File

@ -4,8 +4,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.home;
import android.content.Context;
import android.database.Cursor;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import org.mozilla.gecko.R;
import org.mozilla.gecko.RemoteTabsExpandableListAdapter;
import org.mozilla.gecko.db.RemoteClient;
public abstract class CombinedHistoryItem extends RecyclerView.ViewHolder {
public CombinedHistoryItem(View view) {
@ -16,12 +24,33 @@ public abstract class CombinedHistoryItem extends RecyclerView.ViewHolder {
public HistoryItem(View view) {
super(view);
}
public void bind(Cursor historyCursor) {
final TwoLinePageRow pageRow = (TwoLinePageRow) this.itemView;
pageRow.setShowIcons(true);
pageRow.updateFromCursor(historyCursor);
}
}
public static class ClientItem extends CombinedHistoryItem {
final TextView nameView;
final ImageView deviceTypeView;
final TextView lastModifiedView;
public ClientItem(View view) {
super(view);
nameView = (TextView) view.findViewById(R.id.client);
deviceTypeView = (ImageView) view.findViewById(R.id.device_type);
lastModifiedView = (TextView) view.findViewById(R.id.last_synced);
}
public void bind(RemoteClient client, Context context) {
this.nameView.setText(client.name);
this.nameView.setTextColor(ContextCompat.getColor(context, R.color.placeholder_active_grey));
this.deviceTypeView.setImageResource("desktop".equals(client.deviceType) ? R.drawable.sync_desktop : R.drawable.sync_mobile);
final long now = System.currentTimeMillis();
this.lastModifiedView.setText(RemoteTabsExpandableListAdapter.getLastSyncedString(context, now, client.lastModified));
}
}
}

View File

@ -5,8 +5,130 @@
package org.mozilla.gecko.home;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.R;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.db.RemoteClient;
import java.util.List;
public class CombinedHistoryPanel extends HomeFragment {
private static final String LOGTAG = "GeckoCombinedHistoryPnl";
private final int LOADER_ID_HISTORY = 0;
private final int LOADER_ID_REMOTE = 1;
private CombinedHistoryRecyclerView mRecyclerView;
private CombinedHistoryAdapter mAdapter;
private CursorLoaderCallbacks mCursorLoaderCallbacks;
// The button view for clearing browsing history.
private View mClearHistoryButton;
@Override
protected void load() {}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.home_combined_history_panel, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mRecyclerView = (CombinedHistoryRecyclerView) view.findViewById(R.id.combined_recycler_view);
mAdapter = new CombinedHistoryAdapter(getContext());
mRecyclerView.setAdapter(mAdapter);
mClearHistoryButton = view.findViewById(R.id.clear_history_button);
// TODO: link up click handler for clear history button
// TODO: Handle date headers.
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mCursorLoaderCallbacks = new CursorLoaderCallbacks();
}
@Override
protected void load() {
getLoaderManager().initLoader(LOADER_ID_HISTORY, null, mCursorLoaderCallbacks);
getLoaderManager().initLoader(LOADER_ID_REMOTE, null, mCursorLoaderCallbacks);
}
private static class RemoteTabsCursorLoader extends SimpleCursorLoader {
private final GeckoProfile mProfile;
public RemoteTabsCursorLoader(Context context) {
super(context);
mProfile = GeckoProfile.get(context);
}
@Override
public Cursor loadCursor() {
return mProfile.getDB().getTabsAccessor().getRemoteTabsCursor(getContext());
}
}
private static class HistoryCursorLoader extends SimpleCursorLoader {
// Max number of history results
private static final int HISTORY_LIMIT = 100;
private final BrowserDB mDB;
public HistoryCursorLoader(Context context) {
super(context);
mDB = GeckoProfile.get(context).getDB();
}
@Override
public Cursor loadCursor() {
final ContentResolver cr = getContext().getContentResolver();
// TODO: Handle time bracketing by fetching date ranges from cursor
return mDB.getRecentHistory(cr, HISTORY_LIMIT);
}
}
private class CursorLoaderCallbacks extends TransitionAwareCursorLoaderCallbacks {
private BrowserDB mDB; // Pseudo-final: set in onCreateLoader.
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
if (mDB == null) {
mDB = GeckoProfile.get(getActivity()).getDB();
}
switch (id) {
case LOADER_ID_HISTORY:
return new HistoryCursorLoader(getContext());
case LOADER_ID_REMOTE:
return new RemoteTabsCursorLoader(getContext());
default:
Log.e(LOGTAG, "Unknown loader id!");
return null;
}
}
protected void onLoadFinishedAfterTransitions(Loader<Cursor> loader, Cursor c) {
final int loaderId = loader.getId();
switch (loaderId) {
case LOADER_ID_HISTORY:
mAdapter.setHistory(c);
break;
case LOADER_ID_REMOTE:
final List<RemoteClient> clients = mDB.getTabsAccessor().getClientsFromCursor(c);
// TODO: Handle hidden clients
mAdapter.setClients(clients);
break;
}
}
}
}

View File

@ -41,6 +41,7 @@ public class CombinedHistoryRecyclerView extends RecyclerView
@Override
public boolean onItemLongClicked(RecyclerView recyclerView, int position, View v) {
// TODO: open context menu if not a date title
return showContextMenuForChild(this);
}
}

View File

@ -44,6 +44,7 @@ public final class HomeConfig {
TOP_SITES("top_sites", TopSitesPanel.class),
BOOKMARKS("bookmarks", BookmarksPanel.class),
HISTORY("history", HistoryPanel.class),
COMBINED_HISTORY("combined_history", CombinedHistoryPanel.class),
REMOTE_TABS("remote_tabs", RemoteTabsPanel.class),
READING_LIST("reading_list", ReadingListPanel.class),
RECENT_TABS("recent_tabs", RecentTabsPanel.class),
@ -1594,6 +1595,7 @@ public final class HomeConfig {
private static final String BOOKMARKS_PANEL_ID = "7f6d419a-cd6c-4e34-b26f-f68b1b551907";
private static final String READING_LIST_PANEL_ID = "20f4549a-64ad-4c32-93e4-1dcef792733b";
private static final String HISTORY_PANEL_ID = "f134bf20-11f7-4867-ab8b-e8e705d7fbe8";
private static final String COMBINED_HISTORY_PANEL_ID = "4d716ce2-e063-486d-9e7c-b190d7b04dc6";
private static final String RECENT_TABS_PANEL_ID = "5c2601a5-eedc-4477-b297-ce4cef52adf8";
private static final String REMOTE_TABS_PANEL_ID = "72429afd-8d8b-43d8-9189-14b779c563d0";
@ -1634,6 +1636,7 @@ public final class HomeConfig {
case BOOKMARKS:
return R.string.bookmarks_title;
case COMBINED_HISTORY:
case HISTORY:
return R.string.home_history_title;
@ -1662,6 +1665,9 @@ public final class HomeConfig {
case HISTORY:
return HISTORY_PANEL_ID;
case COMBINED_HISTORY:
return COMBINED_HISTORY_PANEL_ID;
case REMOTE_TABS:
return REMOTE_TABS_PANEL_ID;

View File

@ -75,6 +75,7 @@ public class HomeConfigPrefsBackend implements HomeConfigBackend {
panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.BOOKMARKS));
panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.HISTORY));
panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.COMBINED_HISTORY));
// We disable Synced Tabs for guest mode / restricted profiles.
if (Restrictions.isAllowed(mContext, Restrictable.MODIFY_ACCOUNTS)) {

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<org.mozilla.gecko.home.CombinedHistoryRecyclerView
android:id="@+id/combined_recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<include layout="@layout/home_history_clear_button"/>
</LinearLayout>