1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.support.content.demos;
18 
19 import android.database.Cursor;
20 import android.net.Uri;
21 import android.os.Bundle;
22 import android.view.Menu;
23 import android.view.MenuItem;
24 import android.view.ViewGroup;
25 import android.widget.TextView;
26 
27 import androidx.annotation.NonNull;
28 import androidx.appcompat.app.AppCompatActivity;
29 import androidx.appcompat.widget.Toolbar;
30 import androidx.contentpager.content.ContentPager;
31 import androidx.contentpager.content.ContentPager.ContentCallback;
32 import androidx.contentpager.content.LoaderQueryRunner;
33 import androidx.contentpager.content.Query;
34 import androidx.recyclerview.widget.LinearLayoutManager;
35 import androidx.recyclerview.widget.RecyclerView;
36 
37 import com.google.android.material.floatingactionbutton.FloatingActionButton;
38 import com.google.android.material.snackbar.BaseTransientBottomBar;
39 import com.google.android.material.snackbar.Snackbar;
40 
41 import java.util.Locale;
42 
43 /**
44  * ContentPager demo activity.
45  */
46 public class ContentPagerDemoActivity extends AppCompatActivity {
47 
48     private static final int PAGE_SIZE = 20;
49 
50     private RecyclerView mRecycler;
51     private ContentPager mPager;
52     private Adapter mAdapter;
53     private FloatingActionButton mFab;
54     private Menu mMenu;
55     private int mCurrentPage = -1;
56 
57     @Override
onCreate(Bundle savedInstanceState)58     protected void onCreate(Bundle savedInstanceState) {
59         super.onCreate(savedInstanceState);
60         setContentView(R.layout.activity_demo);
61 
62         ContentPager.QueryRunner runner = new LoaderQueryRunner(this, getLoaderManager());
63         mPager = new ContentPager(getContentResolver(), runner);
64         mAdapter = new Adapter(mPager, PAGE_SIZE);
65 
66         mRecycler = (RecyclerView) findViewById(R.id.list);
67         mRecycler.setLayoutManager(new LinearLayoutManager(this));
68         mRecycler.setAdapter(mAdapter);
69         Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
70         setSupportActionBar(toolbar);
71     }
72 
73     @Override
onDestroy()74     protected void onDestroy() {
75         super.onDestroy();
76         mPager.reset();
77     }
78 
79     @Override
onCreateOptionsMenu(Menu menu)80     public boolean onCreateOptionsMenu(Menu menu) {
81         // Inflate the menu; this adds items to the action bar if it is present.
82         getMenuInflater().inflate(R.menu.menu_demo, menu);
83         mMenu = menu;
84         return true;
85     }
86 
87     @Override
onOptionsItemSelected(MenuItem item)88     public boolean onOptionsItemSelected(MenuItem item) {
89 
90         switch (item.getItemId()) {
91             case R.id.action_load:
92                 onLoadContent();
93                 break;
94             case R.id.action_previous:
95                 onLoadPreviousPage();
96                 break;
97             case R.id.action_next:
98                 onLoadNextPage();
99                 break;
100         }
101         // Handle action bar item clicks here. The action bar will
102         // automatically handle clicks on the Home/Up button, so long
103         // as you specify a parent activity in AndroidManifest.xml.
104         int id = item.getItemId();
105 
106         //noinspection SimplifiableIfStatement
107         if (id == R.id.action_load) {
108             return true;
109         }
110 
111         return super.onOptionsItemSelected(item);
112     }
113 
onLoadContent()114     private void onLoadContent() {
115         mAdapter.reset(UnpagedDemoDataProvider.URI);
116         mCurrentPage = 0;
117         mAdapter.loadPage(mCurrentPage);
118 
119         updateOptionsMenu();
120     }
121 
onLoadNextPage()122     private void onLoadNextPage() {
123         mAdapter.loadPage(mCurrentPage + 1);
124 
125         updateOptionsMenu();
126     }
127 
onLoadPreviousPage()128     private void onLoadPreviousPage() {
129         mAdapter.loadPage(mCurrentPage - 1);
130 
131         updateOptionsMenu();
132     }
133 
updateOptionsMenu()134     private void updateOptionsMenu() {
135         MenuItem prev = mMenu.findItem(R.id.action_previous);
136         MenuItem next = mMenu.findItem(R.id.action_next);
137 
138         int lastPage = (UnpagedDemoDataProvider.TOTAL_SIZE / PAGE_SIZE) - 1;
139         prev.setEnabled(mCurrentPage > 0);
140         next.setEnabled(mCurrentPage < lastPage);
141     }
142 
143     private void msg(String msg) {
144         Snackbar.make(
145                 mRecycler,
146                 msg, BaseTransientBottomBar.LENGTH_LONG)
147                 .setAction("Action", null).show();
148     }
149 
150     private final class Adapter extends RecyclerView.Adapter<Holder> implements ContentCallback {
151 
152         private final ContentPager mPager;
153         private final int mPageSize;
154 
155         private Uri mUri;
156         private Cursor mCursor;
157 
158         private Adapter(ContentPager pager, int pageSize) {
159             mPager = pager;
160             mPageSize = pageSize;
161         }
162 
163         private void reset(Uri uri) {
164             mUri = uri;
165             mCursor = null;
166         }
167 
168         void loadPage(int page) {
169             if (page < 0 || page >= (UnpagedDemoDataProvider.TOTAL_SIZE / PAGE_SIZE)) {
170                 throw new IndexOutOfBoundsException();
171             }
172 
173             mCurrentPage = page;
174             int offset = mCurrentPage * mPageSize;
175             mPager.query(mUri, null, ContentPager.createArgs(offset, mPageSize), null, this);
176         }
177 
178         @Override
179         public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
180             return new Holder(new TextView(ContentPagerDemoActivity.this));
181         }
182 
183         @Override
184         public void onBindViewHolder(Holder holder, int position) {
185             if (!mCursor.moveToPosition(position)) {
186                 holder.view.setText("Nope, couldn't position cursor to: " + position);
187                 return;
188             }
189 
190             holder.view.setText(String.format(Locale.US,
191                     "%d.%d (%d): %s",
192                     mCurrentPage,
193                     mCursor.getInt(0),
194                     mCursor.getLong(2),
195                     mCursor.getString(1)));
196         }
197 
198         @Override
199         public int getItemCount() {
200             return mCursor == null ? 0 : mCursor.getCount();
201         }
202 
203         @Override
204         public void onCursorReady(@NonNull Query query, Cursor cursor) {
205             if (cursor == null) {
206                 msg("Content query returned a null cursor: " + query.getUri());
207             }
208 
209             mCurrentPage = query.getOffset() / mPageSize;
210             mCursor = cursor;
211             notifyDataSetChanged();
212         }
213 
214         private int getCorpusSize(Bundle extras) {
215             return extras.getInt(ContentPager.EXTRA_TOTAL_COUNT, -1);
216         }
217     }
218 
219     private class Holder extends RecyclerView.ViewHolder {
220 
221         public final TextView view;
222 
223         private Holder(TextView view) {
224             super(view);
225             this.view = view;
226         }
227     }
228 }
229