From 1e680128df72a5f7c7226b8874d21a579899de7e Mon Sep 17 00:00:00 2001 From: Artur Dryomov Date: Tue, 16 Jul 2013 00:13:34 +0300 Subject: Add a basic slides grid UI. The slides adapter is using the ViewHolder pattern and view recycling to improve performance. Change-Id: I8f922799dc3af73e9ecaec92ca91eb38e8a784c0 --- .../impressremote/SlidesGridAdapter.java | 108 +++++++++++++ .../impressremote/SlidesGridFragment.java | 170 +++++++++++++++++++++ .../communication/CommunicationService.java | 6 +- .../impressremote/communication/SlideShow.java | 12 +- 4 files changed, 292 insertions(+), 4 deletions(-) create mode 100644 android/sdremote/src/org/libreoffice/impressremote/SlidesGridAdapter.java create mode 100644 android/sdremote/src/org/libreoffice/impressremote/SlidesGridFragment.java (limited to 'android/sdremote/src') diff --git a/android/sdremote/src/org/libreoffice/impressremote/SlidesGridAdapter.java b/android/sdremote/src/org/libreoffice/impressremote/SlidesGridAdapter.java new file mode 100644 index 000000000000..3ccfb51007d6 --- /dev/null +++ b/android/sdremote/src/org/libreoffice/impressremote/SlidesGridAdapter.java @@ -0,0 +1,108 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * 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.libreoffice.impressremote; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import org.libreoffice.impressremote.communication.SlideShow; + +public class SlidesGridAdapter extends BaseAdapter { + private final LayoutInflater mLayoutInflater; + + private final SlideShow mSlideShow; + + public SlidesGridAdapter(Context aContext, SlideShow aSlideShow) { + mLayoutInflater = buildLayoutInflater(aContext); + + mSlideShow = aSlideShow; + } + + private LayoutInflater buildLayoutInflater(Context aContext) { + return (LayoutInflater) aContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } + + @Override + public int getCount() { + return mSlideShow.getSlidesCount(); + } + + @Override + public Object getItem(int aPosition) { + return mSlideShow.getSlidePreview(aPosition); + } + + @Override + public long getItemId(int aPosition) { + return aPosition; + } + + @Override + public View getView(int aPosition, View aConvertView, ViewGroup aViewGroup) { + View aSlideView = getView(aConvertView, aViewGroup); + ViewHolder aSlideViewHolder = getViewHolder(aSlideView); + + if (isSlidePreviewAvailable(aPosition)) { + aSlideViewHolder.aSlidePreview.setImageBitmap(mSlideShow.getSlidePreview(aPosition)); + } else { + aSlideViewHolder.aSlidePreview.setImageResource(R.drawable.slide_unknown); + } + + aSlideViewHolder.aSlideIndex.setText(buildSlideIndex(aPosition)); + + return aSlideView; + } + + private View getView(View aConvertView, ViewGroup aViewGroup) { + if (aConvertView != null) { + return aConvertView; + } + + return mLayoutInflater.inflate(R.layout.view_grid_slide, aViewGroup, false); + } + + private ViewHolder getViewHolder(View aView) { + if (aView.getTag() != null) { + return (ViewHolder) aView.getTag(); + } + + return buildViewHolder(aView); + } + + private static final class ViewHolder { + public ImageView aSlidePreview; + public TextView aSlideIndex; + } + + private ViewHolder buildViewHolder(View aView) { + ViewHolder aViewHolder = new ViewHolder(); + + aViewHolder.aSlidePreview = (ImageView) aView.findViewById(R.id.image_slide_preview); + aViewHolder.aSlideIndex = (TextView) aView.findViewById(R.id.text_slide_index); + + return aViewHolder; + } + + private boolean isSlidePreviewAvailable(int aSlideIndex) { + return mSlideShow.getSlidePreview(aSlideIndex) != null; + } + + private String buildSlideIndex(int aPosition) { + int aHumanSlideIndex = aPosition + 1; + + return Integer.toString(aHumanSlideIndex); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/android/sdremote/src/org/libreoffice/impressremote/SlidesGridFragment.java b/android/sdremote/src/org/libreoffice/impressremote/SlidesGridFragment.java new file mode 100644 index 000000000000..b16b5091a812 --- /dev/null +++ b/android/sdremote/src/org/libreoffice/impressremote/SlidesGridFragment.java @@ -0,0 +1,170 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * 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.libreoffice.impressremote; + +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; +import android.support.v4.content.LocalBroadcastManager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.GridView; + +import com.actionbarsherlock.app.SherlockFragment; +import org.libreoffice.impressremote.communication.CommunicationService; + +public class SlidesGridFragment extends SherlockFragment implements ServiceConnection, AdapterView.OnItemClickListener { + private CommunicationService mCommunicationService; + private BroadcastReceiver mIntentsReceiver; + + public static SlidesGridFragment newInstance() { + return new SlidesGridFragment(); + } + + @Override + public View onCreateView(LayoutInflater aInflater, ViewGroup aContainer, Bundle aSavedInstanceState) { + return aInflater.inflate(R.layout.fragment_slides_grid, aContainer, false); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + bindService(); + } + + private void bindService() { + Intent aServiceIntent = new Intent(getActivity(), CommunicationService.class); + + getActivity().bindService(aServiceIntent, this, Context.BIND_AUTO_CREATE); + } + + @Override + public void onServiceConnected(ComponentName aComponentName, IBinder aBinder) { + CommunicationService.CBinder aServiceBinder = (CommunicationService.CBinder) aBinder; + + mCommunicationService = aServiceBinder.getService(); + + mCommunicationService.getTransmitter().startPresentation(); + + setUpSlidesGrid(); + } + + private void setUpSlidesGrid() { + SlidesGridAdapter aSlidesGridAdapter = new SlidesGridAdapter(getActivity(), + mCommunicationService.getSlideShow()); + + getSlidesGrid().setAdapter(aSlidesGridAdapter); + getSlidesGrid().setOnItemClickListener(this); + } + + private GridView getSlidesGrid() { + return (GridView) getView().findViewById(R.id.grid_slides); + } + + @Override + public void onServiceDisconnected(ComponentName aComponentName) { + mCommunicationService = null; + } + + @Override + public void onResume() { + super.onResume(); + + registerIntentsReceiver(); + } + + private void registerIntentsReceiver() { + mIntentsReceiver = new IntentsReceiver(this); + IntentFilter aIntentFilter = buildIntentsReceiverFilter(); + + getBroadcastManager().registerReceiver(mIntentsReceiver, aIntentFilter); + } + + @Override + public void onItemClick(AdapterView aAdapterView, View aView, int aPosition, long aId) { + mCommunicationService.getTransmitter().setCurrentSlide(aPosition); + } + + private static final class IntentsReceiver extends BroadcastReceiver { + private final SlidesGridFragment mSlidesGridFragment; + + private IntentsReceiver(SlidesGridFragment aSlidesGridFragment) { + mSlidesGridFragment = aSlidesGridFragment; + } + + @Override + public void onReceive(Context aContext, Intent aIntent) { + if (Intents.Actions.SLIDE_PREVIEW.equals(aIntent.getAction())) { + mSlidesGridFragment.refreshSlidesGrid(); + } + } + } + + private IntentFilter buildIntentsReceiverFilter() { + IntentFilter aIntentFilter = new IntentFilter(); + aIntentFilter.addAction(Intents.Actions.SLIDE_PREVIEW); + + return aIntentFilter; + } + + private LocalBroadcastManager getBroadcastManager() { + Context aContext = getActivity().getApplicationContext(); + + return LocalBroadcastManager.getInstance(aContext); + } + + private void refreshSlidesGrid() { + getSlidesGrid().invalidateViews(); + } + + @Override + public void onPause() { + super.onPause(); + + unregisterIntentsReceiver(); + } + + private void unregisterIntentsReceiver() { + try { + getBroadcastManager().unregisterReceiver(mIntentsReceiver); + } catch (IllegalArgumentException e) { + // Receiver not registered. + // Fixed in Honeycomb: Android’s issue #6191. + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + + unbindService(); + } + + private void unbindService() { + if (!isServiceBound()) { + return; + } + + getActivity().unbindService(this); + } + + private boolean isServiceBound() { + return mCommunicationService != null; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java index fa9768a8bb55..3bb00c54e23c 100644 --- a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java +++ b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java @@ -58,6 +58,8 @@ public class CommunicationService extends Service implements Runnable, MessagesL mServersManager = new ServersManager(this); + mSlideShow = new SlideShow(); + mThread = new Thread(this); mThread.start(); } @@ -240,7 +242,7 @@ public class CommunicationService extends Service implements Runnable, MessagesL @Override public void onSlideShowStart(int aSlidesCount, int aCurrentSlideIndex) { - mSlideShow = new SlideShow(); + mSlideShow.cleanUp(); mSlideShow.setSlidesCount(aSlidesCount); Intent aIntent = Intents.buildSlideShowRunningIntent(); @@ -251,7 +253,7 @@ public class CommunicationService extends Service implements Runnable, MessagesL @Override public void onSlideShowFinish() { - mSlideShow = new SlideShow(); + mSlideShow.cleanUp(); Intent aIntent = Intents.buildSlideShowStoppedIntent(); LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent); diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java b/android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java index 347a92c77bf1..f8ae6d898265 100644 --- a/android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java +++ b/android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java @@ -33,7 +33,7 @@ public class SlideShow { } public void setSlidesCount(int aSlidesCount) { - this.mSlidesCount = aSlidesCount; + mSlidesCount = aSlidesCount; } public int getSlidesCount() { @@ -41,7 +41,7 @@ public class SlideShow { } public void setCurrentSlideIndex(int aCurrentSlideIndex) { - this.mCurrentSlideIndex = aCurrentSlideIndex; + mCurrentSlideIndex = aCurrentSlideIndex; } public int getCurrentSlideIndex() { @@ -76,6 +76,14 @@ public class SlideShow { public Timer getTimer() { return mTimer; } + + public void cleanUp() { + mSlidesCount = 0; + mCurrentSlideIndex = 0; + + mSlidePreviews.clear(); + mSlideNotes.clear(); + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit