| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package io.v.android.apps.syncslides.db; |
| |
| import android.os.Handler; |
| import android.os.Looper; |
| import android.util.Log; |
| |
| import com.google.common.collect.Lists; |
| |
| import java.util.List; |
| |
| import io.v.impl.google.naming.NamingUtil; |
| import io.v.v23.context.CancelableVContext; |
| import io.v.v23.context.VContext; |
| import io.v.v23.syncbase.nosql.BatchDatabase; |
| import io.v.v23.syncbase.nosql.ChangeType; |
| import io.v.v23.syncbase.nosql.Database; |
| import io.v.v23.syncbase.nosql.Stream; |
| import io.v.v23.syncbase.nosql.Table; |
| import io.v.v23.syncbase.nosql.WatchChange; |
| import io.v.v23.verror.VException; |
| import io.v.v23.vom.VomUtil; |
| |
| /** |
| * Watches for changes to the CurrentSlide row. |
| */ |
| class CurrentSlideWatcher { |
| |
| private static final String TAG = "CurrentSlideWatcher"; |
| private final CancelableVContext mVContext; |
| private final Database mDB; |
| private final String mDeckId; |
| private final String mPresentationId; |
| private final List<DB.CurrentSlideListener> mListeners; |
| private final Handler mHandler; |
| private VCurrentSlide mCurrentSlide; |
| private Thread mThread; |
| |
| public CurrentSlideWatcher(VContext vContext, Database db, String deckId, |
| String presentationId) { |
| mVContext = vContext.withCancel(); |
| mDB = db; |
| mDeckId = deckId; |
| mPresentationId = presentationId; |
| mListeners = Lists.newArrayList(); |
| mHandler = new Handler(Looper.getMainLooper()); |
| mCurrentSlide = new VCurrentSlide(0); |
| mThread = new Thread(new Runnable() { |
| @Override |
| public void run() { |
| watchCurrentSlide(); |
| } |
| }); |
| } |
| |
| /** |
| * Adds a listener for this deckId/presentationId. |
| * |
| * @param listener notified when the current slide changes |
| */ |
| public void addListener(final DB.CurrentSlideListener listener) { |
| mHandler.post(new Runnable() { |
| @Override |
| public void run() { |
| listener.onChange(mCurrentSlide.getNum()); |
| } |
| }); |
| mListeners.add(listener); |
| if (mListeners.size() == 1) { |
| // The first listener was just added. |
| Log.i(TAG, "Starting thread"); |
| mThread.start(); |
| } |
| } |
| |
| /** |
| * Removes a listener previously added with addListener. If this was the last |
| * listener, no more listeners can be added and the CurrentSlideWatcher |
| * should be discarded. |
| */ |
| public void removeListener(DB.CurrentSlideListener listener) { |
| mListeners.remove(listener); |
| if (mListeners.isEmpty()) { |
| mVContext.cancel(); |
| mThread = null; |
| mHandler.removeCallbacksAndMessages(null); |
| } |
| } |
| |
| /** |
| * Returns true if the number of listeners is greater than zero. |
| */ |
| public boolean hasListeners() { |
| return !mListeners.isEmpty(); |
| } |
| |
| private void notifyListeners(VCurrentSlide slide) { |
| Log.i(TAG, "notifyListeners " + slide); |
| mCurrentSlide = slide; |
| for (DB.CurrentSlideListener listener : mListeners) { |
| Log.i(TAG, "notifying listener " + listener); |
| listener.onChange(mCurrentSlide.getNum()); |
| } |
| } |
| |
| private void watchCurrentSlide() { |
| try { |
| Log.i(TAG, "watchCurrentSlide"); |
| String rowKey = NamingUtil.join(mDeckId, mPresentationId, SyncbaseDB.CURRENT_SLIDE); |
| BatchDatabase batch = mDB.beginBatch(mVContext, null); |
| Table presentations = batch.getTable(SyncbaseDB.PRESENTATIONS_TABLE); |
| if (presentations.getRow(rowKey).exists(mVContext)) { |
| final VCurrentSlide slide = (VCurrentSlide) presentations.get( |
| mVContext, rowKey, VCurrentSlide.class); |
| mHandler.post(new Runnable() { |
| @Override |
| public void run() { |
| notifyListeners(slide); |
| } |
| }); |
| } |
| Stream<WatchChange> changeStream; |
| changeStream = mDB.watch(mVContext, SyncbaseDB.PRESENTATIONS_TABLE, rowKey, |
| batch.getResumeMarker(mVContext)); |
| for (WatchChange change : changeStream) { |
| if (!change.getTableName().equals(SyncbaseDB.PRESENTATIONS_TABLE)) { |
| Log.e(TAG, "Wrong change table name: " + change.getTableName() + ", wanted: " + |
| SyncbaseDB.PRESENTATIONS_TABLE); |
| continue; |
| } |
| final String key = change.getRowName(); |
| Log.i(TAG, "Found change " + key); |
| if (!key.equals(rowKey)) { |
| Log.d(TAG, "Ignoring change: " + key); |
| continue; |
| } |
| if (change.getChangeType().equals(ChangeType.PUT_CHANGE)) { |
| final VCurrentSlide slide2 = (VCurrentSlide) VomUtil.decode( |
| change.getVomValue(), VCurrentSlide.class); |
| mHandler.post(new Runnable() { |
| @Override |
| public void run() { |
| notifyListeners(slide2); |
| } |
| }); |
| } |
| } |
| } catch (VException e) { |
| Log.e(TAG, "Watching failed " + e); |
| } |
| } |
| } |