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 */ 14ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.leanback.widget; 1520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 1620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbournimport android.database.Cursor; 1720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbournimport android.util.LruCache; 1820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 198619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.leanback.database.CursorMapper; 208619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikas 2120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn/** 22a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * An {@link ObjectAdapter} implemented with a {@link Cursor}. 2320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 2420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbournpublic class CursorObjectAdapter extends ObjectAdapter { 2520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn private static final int CACHE_SIZE = 100; 260f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu private Cursor mCursor; 270f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu private CursorMapper mMapper; 280f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu private final LruCache<Integer, Object> mItemCache = new LruCache<Integer, Object>(CACHE_SIZE); 2920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 30beeaa973d1b5bd79ee8ae798141231d9a315eba7Tim Kilbourn /** 31a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Constructs an adapter with the given {@link PresenterSelector}. 32beeaa973d1b5bd79ee8ae798141231d9a315eba7Tim Kilbourn */ 3320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public CursorObjectAdapter(PresenterSelector presenterSelector) { 3420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn super(presenterSelector); 3520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 3620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 37beeaa973d1b5bd79ee8ae798141231d9a315eba7Tim Kilbourn /** 38a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Constructs an adapter that uses the given {@link Presenter} for all items. 39beeaa973d1b5bd79ee8ae798141231d9a315eba7Tim Kilbourn */ 4020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public CursorObjectAdapter(Presenter presenter) { 4120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn super(presenter); 4220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 4320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 44beeaa973d1b5bd79ee8ae798141231d9a315eba7Tim Kilbourn /** 45a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Constructs an adapter. 46beeaa973d1b5bd79ee8ae798141231d9a315eba7Tim Kilbourn */ 4720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public CursorObjectAdapter() { 4820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn super(); 4920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 5020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 5120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn /** 52a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Changes the underlying cursor to a new cursor. If there is 53beeaa973d1b5bd79ee8ae798141231d9a315eba7Tim Kilbourn * an existing cursor it will be closed if it is different than the new 54beeaa973d1b5bd79ee8ae798141231d9a315eba7Tim Kilbourn * cursor. 5520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * 5620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * @param cursor The new cursor to be used. 5720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 5820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public void changeCursor(Cursor cursor) { 5920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn if (cursor == mCursor) { 6020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return; 6120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 622eaaad9c189f1ae42bf6c382a30ccab455030e54Andrew Wilson if (mCursor != null) { 632eaaad9c189f1ae42bf6c382a30ccab455030e54Andrew Wilson mCursor.close(); 642eaaad9c189f1ae42bf6c382a30ccab455030e54Andrew Wilson } 6520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn mCursor = cursor; 6620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn mItemCache.trimToSize(0); 6720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn onCursorChanged(); 6820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 6920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 7020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn /** 7120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Swap in a new Cursor, returning the old Cursor. Unlike changeCursor(Cursor), 7220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * the returned old Cursor is not closed. 7320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * 7420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * @param cursor The new cursor to be used. 7520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 7620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public Cursor swapCursor(Cursor cursor) { 7720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn if (cursor == mCursor) { 7820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return mCursor; 7920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 8020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn Cursor oldCursor = mCursor; 8120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn mCursor = cursor; 8220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn mItemCache.trimToSize(0); 8320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn onCursorChanged(); 8420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return oldCursor; 8520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 8620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 8720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn /** 8820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Called whenever the cursor changes. 8920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 9020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn protected void onCursorChanged() { 9120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn notifyChanged(); 9220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 9320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 9420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn /** 95a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Returns the {@link Cursor} backing the adapter. 9620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 970f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu public final Cursor getCursor() { 9820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return mCursor; 9920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 10020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 10120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn /** 10220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Sets the {@link CursorMapper} used to convert {@link Cursor} rows into 10320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Objects. 10420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 1050f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu public final void setMapper(CursorMapper mapper) { 106b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson boolean changed = mMapper != mapper; 10720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn mMapper = mapper; 108b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson 109b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson if (changed) { 110b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson onMapperChanged(); 111b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson } 112b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson } 113b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson 114b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson /** 115b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson * Called when {@link #setMapper(CursorMapper)} is called and a different 116b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson * mapper is provided. 117b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson */ 118b3451baf39c3b17972e7826baee90be4b1cd2626Justin Mattson protected void onMapperChanged() { 11920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 12020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 12120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn /** 122a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Returns the {@link CursorMapper} used to convert {@link Cursor} rows into 12320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Objects. 12420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 1250f1fa0dfa946ddc8afb6af26a4dd1a4d01dca10fDake Gu public final CursorMapper getMapper() { 12620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return mMapper; 12720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 12820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 12920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn @Override 13020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public int size() { 13120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn if (mCursor == null) { 13220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return 0; 13320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 13420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return mCursor.getCount(); 13520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 13620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 13720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn @Override 13820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public Object get(int index) { 13920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn if (mCursor == null) { 14020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return null; 14120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 14220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn if (!mCursor.moveToPosition(index)) { 14320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn throw new ArrayIndexOutOfBoundsException(); 14420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 14520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn Object item = mItemCache.get(index); 14620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn if (item != null) { 14720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return item; 14820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 14920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn item = mMapper.convert(mCursor); 15020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn mItemCache.put(index, item); 15120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return item; 15220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 15320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 15420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn /** 15520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Closes this adapter, closing the backing {@link Cursor} as well. 15620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 15720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public void close() { 15820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn if (mCursor != null) { 15920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn mCursor.close(); 16020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn mCursor = null; 16120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 16220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 16320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn 16420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn /** 165a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Returns true if the adapter, and hence the backing {@link Cursor}, is closed; false 166a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * otherwise. 16720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */ 16820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn public boolean isClosed() { 16920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn return mCursor == null || mCursor.isClosed(); 17020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn } 171c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson 172c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson /** 173a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Removes an item from the cache. This will force the item to be re-read 174377357a8c26c8c54ba8cb876ae775265635a8448Elliot Waite * from the data source the next time {@link #get(int)} is called. 175c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson */ 176c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson protected final void invalidateCache(int index) { 177c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson mItemCache.remove(index); 178c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson } 179c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson 180c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson /** 181a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Removes {@code count} items starting at {@code index}. 182c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson */ 183c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson protected final void invalidateCache(int index, int count) { 184c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson for (int limit = count + index; index < limit; index++) { 185c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson invalidateCache(index); 186c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson } 187c251a00602f6872d07e5b464ce7c67e78696438eJustin Mattson } 1880674181fa96779197f965dd4efc47bfd90cd085esusnata 1890674181fa96779197f965dd4efc47bfd90cd085esusnata @Override 1900674181fa96779197f965dd4efc47bfd90cd085esusnata public boolean isImmediateNotifySupported() { 1910674181fa96779197f965dd4efc47bfd90cd085esusnata return true; 1920674181fa96779197f965dd4efc47bfd90cd085esusnata } 19320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn} 194