From f54098165fd81ee5769a5ad7359f6c092e88527e Mon Sep 17 00:00:00 2001 From: Nick Alexander Date: Thu, 4 Sep 2014 15:32:29 -0700 Subject: [PATCH] Bug 1014994 - Part 4: Display list of Remote Tabs when possible. r=margaret --- .../RemoteTabsExpandableListFragment.java | 184 ++++++++++++++++++ mobile/android/base/home/RemoteTabsPanel.java | 4 +- mobile/android/base/moz.build | 1 + .../drawable-hdpi/icon_remote_tabs_empty.png | Bin 0 -> 744 bytes .../drawable-mdpi/icon_remote_tabs_empty.png | Bin 0 -> 645 bytes .../drawable-xhdpi/icon_remote_tabs_empty.png | Bin 0 -> 947 bytes .../layout/home_remote_tabs_child.xml | 10 + .../layout/home_remote_tabs_group.xml | 45 +++++ .../layout/home_remote_tabs_list_panel.xml | 28 +++ .../android/base/resources/values/styles.xml | 10 + 10 files changed, 279 insertions(+), 3 deletions(-) create mode 100644 mobile/android/base/home/RemoteTabsExpandableListFragment.java create mode 100644 mobile/android/base/resources/drawable-hdpi/icon_remote_tabs_empty.png create mode 100644 mobile/android/base/resources/drawable-mdpi/icon_remote_tabs_empty.png create mode 100644 mobile/android/base/resources/drawable-xhdpi/icon_remote_tabs_empty.png create mode 100644 mobile/android/base/resources/layout/home_remote_tabs_child.xml create mode 100644 mobile/android/base/resources/layout/home_remote_tabs_group.xml create mode 100644 mobile/android/base/resources/layout/home_remote_tabs_list_panel.xml diff --git a/mobile/android/base/home/RemoteTabsExpandableListFragment.java b/mobile/android/base/home/RemoteTabsExpandableListFragment.java new file mode 100644 index 00000000000..3e22083954a --- /dev/null +++ b/mobile/android/base/home/RemoteTabsExpandableListFragment.java @@ -0,0 +1,184 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * 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/. */ + +package org.mozilla.gecko.home; + +import java.util.EnumSet; +import java.util.List; + +import org.mozilla.gecko.R; +import org.mozilla.gecko.RemoteTabsExpandableListAdapter; +import org.mozilla.gecko.TabsAccessor; +import org.mozilla.gecko.TabsAccessor.RemoteClient; +import org.mozilla.gecko.TabsAccessor.RemoteTab; +import org.mozilla.gecko.Telemetry; +import org.mozilla.gecko.TelemetryContract; +import org.mozilla.gecko.home.HomePager.OnUrlOpenListener; + +import android.content.Context; +import android.database.Cursor; +import android.os.Bundle; +import android.support.v4.app.LoaderManager.LoaderCallbacks; +import android.support.v4.content.Loader; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewStub; +import android.widget.ExpandableListAdapter; +import android.widget.ExpandableListView; +import android.widget.ExpandableListView.OnChildClickListener; +import android.widget.ExpandableListView.OnGroupClickListener; +import android.widget.ImageView; +import android.widget.TextView; + +/** + * Fragment that displays tabs from other devices in an ExpandableListView. + *

+ * This is intended to be used on phones, and possibly in portrait mode on tablets. + */ +public class RemoteTabsExpandableListFragment extends HomeFragment { + // Logging tag name. + @SuppressWarnings("unused") + private static final String LOGTAG = "GeckoRemoteTabsExpList"; + + // Cursor loader ID. + private static final int LOADER_ID_REMOTE_TABS = 0; + + // Adapter for the list of remote tabs. + private RemoteTabsExpandableListAdapter mAdapter; + + // The view shown by the fragment. + private ExpandableListView mList; + + // Reference to the View to display when there are no results. + private View mEmptyView; + + // Callbacks used for the loader. + private CursorLoaderCallbacks mCursorLoaderCallbacks; + + public static RemoteTabsExpandableListFragment newInstance() { + return new RemoteTabsExpandableListFragment(); + } + + public RemoteTabsExpandableListFragment() { + super(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(R.layout.home_remote_tabs_list_panel, container, false); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + mList = (ExpandableListView) view.findViewById(R.id.list); + mList.setTag(HomePager.LIST_TAG_REMOTE_TABS); + + mList.setOnChildClickListener(new OnChildClickListener() { + @Override + public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { + final ExpandableListAdapter adapter = parent.getExpandableListAdapter(); + final RemoteTab tab = (RemoteTab) adapter.getChild(groupPosition, childPosition); + if (tab == null) { + return false; + } + + Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.LIST_ITEM); + + // This item is a TwoLinePageRow, so we allow switch-to-tab. + mUrlOpenListener.onUrlOpen(tab.url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB)); + return true; + } + }); + + mList.setOnGroupClickListener(new OnGroupClickListener() { + @Override + public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) { + // Since we don't indicate the expansion state yet, don't allow + // collapsing groups at all. + return true; + } + }); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + mList = null; + mEmptyView = null; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + // Intialize adapter + mAdapter = new RemoteTabsExpandableListAdapter(R.layout.home_remote_tabs_group, R.layout.home_remote_tabs_child, null); + mList.setAdapter(mAdapter); + + // Create callbacks before the initial loader is started + mCursorLoaderCallbacks = new CursorLoaderCallbacks(); + loadIfVisible(); + } + + private void updateUiFromClients(List clients) { + if (clients != null && !clients.isEmpty()) { + for (int i = 0; i < mList.getExpandableListAdapter().getGroupCount(); i++) { + mList.expandGroup(i); + } + return; + } + + // Cursor is empty, so set the empty view if it hasn't been set already. + if (mEmptyView == null) { + // Set empty panel view. We delay this so that the empty view won't flash. + final ViewStub emptyViewStub = (ViewStub) getView().findViewById(R.id.home_empty_view_stub); + mEmptyView = emptyViewStub.inflate(); + + final ImageView emptyIcon = (ImageView) mEmptyView.findViewById(R.id.home_empty_image); + emptyIcon.setImageResource(R.drawable.icon_remote_tabs_empty); + + final TextView emptyText = (TextView) mEmptyView.findViewById(R.id.home_empty_text); + emptyText.setText(R.string.home_remote_tabs_empty); + + mList.setEmptyView(mEmptyView); + } + } + + @Override + protected void load() { + getLoaderManager().initLoader(LOADER_ID_REMOTE_TABS, null, mCursorLoaderCallbacks); + } + + private static class RemoteTabsCursorLoader extends SimpleCursorLoader { + public RemoteTabsCursorLoader(Context context) { + super(context); + } + + @Override + public Cursor loadCursor() { + return TabsAccessor.getRemoteTabsCursor(getContext()); + } + } + + private class CursorLoaderCallbacks implements LoaderCallbacks { + @Override + public Loader onCreateLoader(int id, Bundle args) { + return new RemoteTabsCursorLoader(getActivity()); + } + + @Override + public void onLoadFinished(Loader loader, Cursor c) { + final List clients = TabsAccessor.getClientsFromCursor(c); + mAdapter.replaceClients(clients); + updateUiFromClients(clients); + } + + @Override + public void onLoaderReset(Loader loader) { + mAdapter.replaceClients(null); + } + } +} diff --git a/mobile/android/base/home/RemoteTabsPanel.java b/mobile/android/base/home/RemoteTabsPanel.java index aa5e1e71387..9cdea093d4f 100644 --- a/mobile/android/base/home/RemoteTabsPanel.java +++ b/mobile/android/base/home/RemoteTabsPanel.java @@ -145,9 +145,7 @@ public class RemoteTabsPanel extends HomeFragment { switch (action) { case None: - // This is only here to allow splitting commits. It will be replaced - // with the list of Remote Tabs in the next commits. - return RemoteTabsStaticFragment.newInstance(R.layout.remote_tabs_needs_upgrade); + return new RemoteTabsExpandableListFragment(); case NeedsVerification: return RemoteTabsStaticFragment.newInstance(R.layout.remote_tabs_needs_verification); case NeedsPassword: diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build index 313de9061e5..26822db1cb5 100644 --- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -297,6 +297,7 @@ gbjar.sources += [ 'home/ReadingListPanel.java', 'home/ReadingListRow.java', 'home/RecentTabsPanel.java', + 'home/RemoteTabsExpandableListFragment.java', 'home/RemoteTabsPanel.java', 'home/RemoteTabsStaticFragment.java', 'home/SearchEngine.java', diff --git a/mobile/android/base/resources/drawable-hdpi/icon_remote_tabs_empty.png b/mobile/android/base/resources/drawable-hdpi/icon_remote_tabs_empty.png new file mode 100644 index 0000000000000000000000000000000000000000..7f96aee70ef0644b3e9766f1a92f8d2ae9e4cf9f GIT binary patch literal 744 zcmeAS@N?(olHy`uVBq!ia0vp^?I6s-3?#WNcUb_bkN}?$S0H`#!Y%5e^A3eRKyzhE zg8YIRmU68VRbbuRZ#qv}AftOz!!-TsB#(lY7S;JAqwj)6KJg*6sXpnfu%qivVklrBi~uG?#{al5jfe zzwBjR#Dvn7kyZDW#e|h;Sa07sNXT~DNx^Yl3CfQ&s_a*$1x^{gDZ|DH_Zw(RcpGg!p-1$bcfvJ zX-v9mwvSiwNN7$-Dq4Dgb@CJ@<$$0Cr#>cWBz#EHepoH#b?3vB;FMSU0uM2YSU%QV z=+U;^*tPGKMP_?h1_E(B(75<+E_ZaM`;BjP^OWTLB~^I>f)7OQF%jXY_}It9d?A02 zc&Uhn!Ai{w%-3>utEcq^>fJ8mHx+Zxx8?iUSW;1(7^1&>BU`t5UBZzEACH;!?094z z|6#S!arqqClN)Au{5xMfchmdE)puSPUYA~HWc%z-#tyAJAD6w=OZ~M{@0}R;pPdnv z|K4moaIahOZ%EuO6h(WvH9`;=5@^l>g4a=X;%>XV&h%K`uyzf z*mXS_-_FYy&3?Wy(60Zato?j1S=;sAvNiRBw}0$zU)pgr?CQq-)g7`m_pkH4y#Pmj z`|ZX51s4~2HlBKSce;>uRlSdvb;W$YHw}LeG2WKlm_IW?_~pOM-Sz)N9Cr0btIIz; yRD0*`B==0Sx9a^XA2LnvQ?&t;ucLK6Ux{cnZ< literal 0 HcmV?d00001 diff --git a/mobile/android/base/resources/drawable-mdpi/icon_remote_tabs_empty.png b/mobile/android/base/resources/drawable-mdpi/icon_remote_tabs_empty.png new file mode 100644 index 0000000000000000000000000000000000000000..9020e1e0874d126d7854b38d6893fd31ee629183 GIT binary patch literal 645 zcmeAS@N?(olHy`uVBq!ia0vp^Q6S903?%u>HW~n_%mAMdS0H`#!Yw+Wbp>{jK+BX% zg8YIR=CKsnNKD=wQn#U!t1VGBv&V6b2cNK(+Qfy1%LAv)indsivgpr01_s6zo-U3d z6^w6hoX%TqAkz9!RNBB$?T$WUk>|btiv3R%S|;y(z3P(WmQUt?pQ=7_%w}~IU^%$n zFn#i^%iA{{IH$pX>m|Eo(sGS_zwltQ+X_p5Es4(Y>nb?3?5fLjriPFuQmd!DD_^6u z%R3=#%hKl1j9ssprbUY6x-FB?t(HAEbxX{7gF??kr*_62oD>tkU}s6o)PlckuUA+E z*w3|NNVM{4e`#>HK()E_SrwD^12?a5ZLqB5%z8!!|ot*9nI2 zif7%o=go4)wl(!M&Ik)i94az^Hcmz}TARpt1sw6BVLur%ZHUhlhy z1+TAM-1qRstM1FUnGW7hdbBt0L2rj__IKg8kvmK5lGRsTnXPrGe8!*G-#1SPInVN^ z$kl73)=RyIqMA{c4@-$Ax10|&)O+K;f69l-s(aT(uWSGK^QS&}2H$0%yZ>K*dGzy% zwL9wC_^ZFX`x)qT==mZE)-~+cut>c^A;s$4){)~KqAI41z98L8NbqP8@4hqEpqnN?d)z4*}Q$iB}3!Y16 literal 0 HcmV?d00001 diff --git a/mobile/android/base/resources/drawable-xhdpi/icon_remote_tabs_empty.png b/mobile/android/base/resources/drawable-xhdpi/icon_remote_tabs_empty.png new file mode 100644 index 0000000000000000000000000000000000000000..2bdc3daea5d2d1df91ee98e4852f5ddb4a211536 GIT binary patch literal 947 zcmeAS@N?(olHy`uVBq!ia0vp^TR@nD8Ax&oe*=;XEa{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaMQ0(?STf%MS}wS0{LP}7RfV^&$EPl0{B4@E)p%t`)^g9SDzDEjDzgjd zOxgQ8CV6_v`SNGEvw2^C>$&%666?|#+kWX4^={V72D~`X+=C_WqB#EhUok1Ki2e*v)OO-(ETB6kShD znz;9osQ&!R(@dvNqD;YxvX + + + diff --git a/mobile/android/base/resources/layout/home_remote_tabs_group.xml b/mobile/android/base/resources/layout/home_remote_tabs_group.xml new file mode 100644 index 00000000000..f3ce5d56777 --- /dev/null +++ b/mobile/android/base/resources/layout/home_remote_tabs_group.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + diff --git a/mobile/android/base/resources/layout/home_remote_tabs_list_panel.xml b/mobile/android/base/resources/layout/home_remote_tabs_list_panel.xml new file mode 100644 index 00000000000..1475bcd2969 --- /dev/null +++ b/mobile/android/base/resources/layout/home_remote_tabs_list_panel.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + diff --git a/mobile/android/base/resources/values/styles.xml b/mobile/android/base/resources/values/styles.xml index ee14d46143e..4677759a040 100644 --- a/mobile/android/base/resources/values/styles.xml +++ b/mobile/android/base/resources/values/styles.xml @@ -576,6 +576,16 @@ wrap_content + + + +