120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn/* 220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Copyright (C) 2014 The Android Open Source Project 320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * 420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * in compliance with the License. You may obtain a copy of the License at 620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * 720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * http://www.apache.org/licenses/LICENSE-2.0 820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * 920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Unless required by applicable law or agreed to in writing, software distributed under the License 1020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 1120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * or implied. See the License for the specific language governing permissions and limitations under 1220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * the License. 1320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 1420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbournpackage android.support.v17.leanback.widget; 1520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 1620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbournimport android.database.Cursor; 1720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbournimport android.support.v17.leanback.database.CursorMapper; 1820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbournimport android.util.LruCache; 1920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 2020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn/** 21a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * An {@link ObjectAdapter} implemented with a {@link Cursor}. 2220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 2320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbournpublic class CursorObjectAdapter extends ObjectAdapter { 2420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn private static final int CACHE_SIZE = 100; 250f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu private Cursor mCursor; 260f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu private CursorMapper mMapper; 270f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu private final LruCache<Integer, Object> mItemCache = new LruCache<Integer, Object>(CACHE_SIZE); 2820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 29beeaa973d1b5bd79ee8ae798141231d9a315eba7Tim Kilbourn /** 30a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Constructs an adapter with the given {@link PresenterSelector}. 31beeaa973d1b5bd79ee8ae798141231d9a315eba7Tim Kilbourn */ 3220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public CursorObjectAdapter(PresenterSelector presenterSelector) { 3320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn super(presenterSelector); 3420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 3520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 36beeaa973d1b5bd79ee8ae798141231d9a315eba7Tim Kilbourn /** 37a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Constructs an adapter that uses the given {@link Presenter} for all items. 38beeaa973d1b5bd79ee8ae798141231d9a315eba7Tim Kilbourn */ 3920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public CursorObjectAdapter(Presenter presenter) { 4020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn super(presenter); 4120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 4220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 43beeaa973d1b5bd79ee8ae798141231d9a315eba7Tim Kilbourn /** 44a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Constructs an adapter. 45beeaa973d1b5bd79ee8ae798141231d9a315eba7Tim Kilbourn */ 4620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public CursorObjectAdapter() { 4720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn super(); 4820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 4920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 5020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn /** 51a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Changes the underlying cursor to a new cursor. If there is 52beeaa973d1b5bd79ee8ae798141231d9a315eba7Tim Kilbourn * an existing cursor it will be closed if it is different than the new 53beeaa973d1b5bd79ee8ae798141231d9a315eba7Tim Kilbourn * cursor. 5420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * 5520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * @param cursor The new cursor to be used. 5620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 5720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public void changeCursor(Cursor cursor) { 5820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn if (cursor == mCursor) { 5920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return; 6020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 612eaaad9c189f1ae42bf6c382a30ccab455030e54Andrew Wilson if (mCursor != null) { 622eaaad9c189f1ae42bf6c382a30ccab455030e54Andrew Wilson mCursor.close(); 632eaaad9c189f1ae42bf6c382a30ccab455030e54Andrew Wilson } 6420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn mCursor = cursor; 6520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn mItemCache.trimToSize(0); 6620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn onCursorChanged(); 6720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 6820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 6920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn /** 7020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Swap in a new Cursor, returning the old Cursor. Unlike changeCursor(Cursor), 7120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * the returned old Cursor is not closed. 7220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * 7320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * @param cursor The new cursor to be used. 7420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 7520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public Cursor swapCursor(Cursor cursor) { 7620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn if (cursor == mCursor) { 7720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return mCursor; 7820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 7920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn Cursor oldCursor = mCursor; 8020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn mCursor = cursor; 8120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn mItemCache.trimToSize(0); 8220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn onCursorChanged(); 8320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return oldCursor; 8420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 8520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 8620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn /** 8720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Called whenever the cursor changes. 8820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 8920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn protected void onCursorChanged() { 9020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn notifyChanged(); 9120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 9220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 9320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn /** 94a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Returns the {@link Cursor} backing the adapter. 9520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 960f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu public final Cursor getCursor() { 9720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return mCursor; 9820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 9920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 10020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn /** 10120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Sets the {@link CursorMapper} used to convert {@link Cursor} rows into 10220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Objects. 10320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 1040f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu public final void setMapper(CursorMapper mapper) { 105b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson boolean changed = mMapper != mapper; 10620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn mMapper = mapper; 107b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson 108b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson if (changed) { 109b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson onMapperChanged(); 110b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson } 111b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson } 112b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson 113b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson /** 114b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson * Called when {@link #setMapper(CursorMapper)} is called and a different 115b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson * mapper is provided. 116b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson */ 117b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson protected void onMapperChanged() { 11820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 11920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 12020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn /** 121a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Returns the {@link CursorMapper} used to convert {@link Cursor} rows into 12220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Objects. 12320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 1240f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu public final CursorMapper getMapper() { 12520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return mMapper; 12620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 12720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 12820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn @Override 12920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public int size() { 13020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn if (mCursor == null) { 13120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return 0; 13220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 13320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return mCursor.getCount(); 13420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 13520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 13620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn @Override 13720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public Object get(int index) { 13820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn if (mCursor == null) { 13920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return null; 14020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 14120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn if (!mCursor.moveToPosition(index)) { 14220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn throw new ArrayIndexOutOfBoundsException(); 14320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 14420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn Object item = mItemCache.get(index); 14520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn if (item != null) { 14620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return item; 14720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 14820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn item = mMapper.convert(mCursor); 14920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn mItemCache.put(index, item); 15020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return item; 15120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 15220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 15320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn /** 15420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Closes this adapter, closing the backing {@link Cursor} as well. 15520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 15620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public void close() { 15720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn if (mCursor != null) { 15820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn mCursor.close(); 15920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn mCursor = null; 16020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 16120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 16220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 16320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn /** 164a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Returns true if the adapter, and hence the backing {@link Cursor}, is closed; false 165a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * otherwise. 16620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 16720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public boolean isClosed() { 16820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return mCursor == null || mCursor.isClosed(); 16920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 170c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson 171c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson /** 172a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Removes an item from the cache. This will force the item to be re-read 173377357a8c26c8c54ba8cb876ae775265635a8448Elliot Waite * from the data source the next time {@link #get(int)} is called. 174c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson */ 175c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson protected final void invalidateCache(int index) { 176c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson mItemCache.remove(index); 177c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson } 178c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson 179c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson /** 180a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Removes {@code count} items starting at {@code index}. 181c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson */ 182c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson protected final void invalidateCache(int index, int count) { 183c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson for (int limit = count + index; index < limit; index++) { 184c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson invalidateCache(index); 185c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson } 186c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson } 1870674181fa96779197f965dd4efc47bfd90cd085esusnata 1880674181fa96779197f965dd4efc47bfd90cd085esusnata @Override 1890674181fa96779197f965dd4efc47bfd90cd085esusnata public boolean isImmediateNotifySupported() { 1900674181fa96779197f965dd4efc47bfd90cd085esusnata return true; 1910674181fa96779197f965dd4efc47bfd90cd085esusnata } 19220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn} 193