Java tutorial
/* * Twidere - Twitter client for Android * * Copyright (C) 2012 Mariotaku Lee <mariotaku.lee@gmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.mariotaku.twidere.activity; import static org.mariotaku.twidere.util.Utils.buildDirectMessageConversationsEntryUri; import static org.mariotaku.twidere.util.Utils.getActivatedAccountIds; import static org.mariotaku.twidere.util.Utils.isMyActivatedAccount; import org.mariotaku.actionbarcompat.ActionBar; import org.mariotaku.twidere.R; import org.mariotaku.twidere.adapter.DirectMessagesEntryAdapter; import org.mariotaku.twidere.fragment.DirectMessagesConversationFragment; import org.mariotaku.twidere.provider.TweetStore.Accounts; import org.mariotaku.twidere.provider.TweetStore.DirectMessages; import org.mariotaku.twidere.util.LazyImageLoader; import org.mariotaku.twidere.util.ServiceInterface; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; import android.support.v4.app.FragmentTransaction; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.widget.SimpleCursorAdapter; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.Window; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.Button; import android.widget.ListView; import android.widget.Spinner; public class DirectMessagesActivity extends BaseActivity implements LoaderCallbacks<Cursor>, OnScrollListener, OnItemClickListener, OnClickListener, OnItemSelectedListener { private ServiceInterface mService; private SharedPreferences mPreferences; private Button mAccountConfirmButton; private Spinner mAccountSelector; private View mAccountSelectContainer, mDirectMessagesContainer; private Handler mHandler; private Runnable mTicker; private ListView mListView; private volatile boolean mBusy, mTickerStopped, mReachedBottom, mNotReachedBottomBefore = true; private DirectMessagesEntryAdapter mAdapter; private static final long TICKER_DURATION = 5000L; private final Bundle mArguments = new Bundle(); private long mAccountId; private DirectMessagesConversationFragment mDetailsFragment; private BroadcastReceiver mStatusReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (BROADCAST_RECEIVED_DIRECT_MESSAGES_DATABASE_UPDATED.equals(action) || BROADCAST_SENT_DIRECT_MESSAGES_DATABASE_UPDATED.equals(action)) { getSupportLoaderManager().restartLoader(LOADER_ID_DIRECT_MESSAGES, null, DirectMessagesActivity.this); } else if (BROADCAST_REFRESHSTATE_CHANGED.equals(action)) { setProgressBarIndeterminateVisibility( mService.isReceivedDirectMessagesRefreshing() || mService.isSentDirectMessagesRefreshing()); } } }; private AccountsAdapter mAccountsAdapter; private Cursor mAccountsCursor; private final static int LOADER_ID_ACCOUNTS = 1; private final static int LOADER_ID_DIRECT_MESSAGES = 2; @Override public void onClick(View view) { switch (view.getId()) { case R.id.account_confirm: { if (mAccountsCursor == null || mAccountsCursor.isClosed()) return; mAccountId = mAccountsCursor.getLong(mAccountsCursor.getColumnIndex(Accounts.USER_ID)); final boolean is_my_activated_account = isMyActivatedAccount(this, mAccountId); if (is_my_activated_account) { mArguments.putLong(INTENT_KEY_ACCOUNT_ID, mAccountId); } mDirectMessagesContainer.setVisibility(is_my_activated_account ? View.VISIBLE : View.GONE); mAccountSelectContainer.setVisibility(!is_my_activated_account ? View.VISIBLE : View.GONE); getSupportLoaderManager().restartLoader(LOADER_ID_DIRECT_MESSAGES, null, this); break; } } } @Override public void onCreate(Bundle savedInstanceState) { requestSupportWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); mService = getTwidereApplication().getServiceInterface(); super.onCreate(savedInstanceState); final Intent intent = getIntent(); final Bundle args = savedInstanceState == null ? intent.getExtras() : savedInstanceState; mAccountId = args != null ? args.getLong(INTENT_KEY_ACCOUNT_ID, -1) : intent.getLongExtra(INTENT_KEY_ACCOUNT_ID, -1); mArguments.clear(); if (args != null) { mArguments.putAll(args); } mService.clearNotification(NOTIFICATION_ID_DIRECT_MESSAGES); setContentView(R.layout.direct_messages); final ActionBar actionbar = getSupportActionBar(); actionbar.setDisplayShowTitleEnabled(true); actionbar.setDisplayHomeAsUpEnabled(true); final LazyImageLoader imageloader = getTwidereApplication().getProfileImageLoader(); mAdapter = new DirectMessagesEntryAdapter(this, imageloader); mDirectMessagesContainer = findViewById(R.id.direct_messages_content); mAccountSelectContainer = findViewById(R.id.account_select_container); mListView = (ListView) findViewById(android.R.id.list); mAccountConfirmButton = (Button) findViewById(R.id.account_confirm); mAccountConfirmButton.setOnClickListener(this); mAccountSelector = (Spinner) findViewById(R.id.account_selector); mListView.setAdapter(mAdapter); mListView.setOnScrollListener(this); mListView.setOnItemClickListener(this); final long[] activated_ids = getActivatedAccountIds(this); if (!isMyActivatedAccount(this, mAccountId) && activated_ids.length == 1) { mAccountId = activated_ids[0]; } final boolean is_my_activated_account = isMyActivatedAccount(this, mAccountId); if (is_my_activated_account) { mArguments.putLong(INTENT_KEY_ACCOUNT_ID, mAccountId); } mDirectMessagesContainer.setVisibility(is_my_activated_account ? View.VISIBLE : View.GONE); mAccountSelectContainer.setVisibility(!is_my_activated_account ? View.VISIBLE : View.GONE); if (!is_my_activated_account) { mAccountsAdapter = new AccountsAdapter(this); mAccountSelector.setAdapter(mAccountsAdapter); mAccountSelector.setOnItemSelectedListener(this); getSupportLoaderManager().initLoader(LOADER_ID_ACCOUNTS, null, this); } getSupportLoaderManager().initLoader(LOADER_ID_DIRECT_MESSAGES, null, this); } @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { switch (id) { case LOADER_ID_ACCOUNTS: { final Uri uri = Accounts.CONTENT_URI; final String[] cols = Accounts.COLUMNS; final String where = Accounts.IS_ACTIVATED + " = 1"; return new CursorLoader(DirectMessagesActivity.this, uri, cols, where, null, null); } case LOADER_ID_DIRECT_MESSAGES: default: { final Uri uri = buildDirectMessageConversationsEntryUri(mAccountId); return new CursorLoader(this, uri, null, null, null, null); } } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_direct_messages, menu); return super.onCreateOptionsMenu(menu); } @Override public void onItemClick(AdapterView<?> adapter, View view, int position, long id) { final long conversation_id = mAdapter.findConversationId(id); if (conversation_id > 0) { openDirectMessagesConversation(mAccountId, conversation_id); } } @Override public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { if (mAccountsCursor == null || mAccountsCursor.isClosed()) return; mAccountsCursor.moveToPosition(pos); } @Override public void onLoaderReset(Loader<Cursor> loader) { switch (loader.getId()) { case LOADER_ID_ACCOUNTS: { mAccountsCursor = null; mAccountsAdapter.changeCursor(null); } case LOADER_ID_DIRECT_MESSAGES: { mAdapter.changeCursor(null); } } } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { switch (loader.getId()) { case LOADER_ID_ACCOUNTS: { mAccountsCursor = cursor; mAccountsAdapter.changeCursor(cursor); } case LOADER_ID_DIRECT_MESSAGES: { mAdapter.changeCursor(cursor); } } } @Override public void onNothingSelected(AdapterView<?> parent) { // Another interface callback } @Override public boolean onOptionsItemSelected(MenuItem item) { final boolean is_my_activated_account = isMyActivatedAccount(this, mAccountId); switch (item.getItemId()) { case MENU_HOME: { onBackPressed(); break; } case MENU_REFRESH: { if (mService == null || !is_my_activated_account) return false; mService.getReceivedDirectMessages(new long[] { mAccountId }, null); mService.getSentDirectMessages(new long[] { mAccountId }, null); break; } case MENU_COMPOSE: { if (!is_my_activated_account) return false; openDirectMessagesConversation(mAccountId, -1); break; } case MENU_LOAD_MORE: { if (mService == null || !is_my_activated_account) return false; final ContentResolver resolver = getContentResolver(); final String where = DirectMessages.ACCOUNT_ID + " = " + mAccountId; final String[] cols = new String[] { "MIN(" + DirectMessages.MESSAGE_ID + ")" }; final Cursor inbox_cur = resolver.query(DirectMessages.Inbox.CONTENT_URI, cols, where, null, null); final Cursor outbox_cur = resolver.query(DirectMessages.Outbox.CONTENT_URI, cols, where, null, null); inbox_cur.moveToFirst(); final long inbox_min_id = inbox_cur.getLong(0); if (inbox_min_id > 0) { mService.getReceivedDirectMessages(new long[] { mAccountId }, new long[] { inbox_min_id }); } outbox_cur.moveToFirst(); final long outbox_min_id = outbox_cur.getLong(0); if (outbox_min_id > 0) { mService.getSentDirectMessages(new long[] { mAccountId }, new long[] { outbox_min_id }); } inbox_cur.close(); outbox_cur.close(); break; } } return super.onOptionsItemSelected(item); } @Override public void onResume() { super.onResume(); final float text_size = mPreferences.getFloat(PREFERENCE_KEY_TEXT_SIZE, PREFERENCE_DEFAULT_TEXT_SIZE); final boolean display_profile_image = mPreferences.getBoolean(PREFERENCE_KEY_DISPLAY_PROFILE_IMAGE, true); final boolean hires_profile_image = mPreferences.getBoolean(PREFERENCE_KEY_HIRES_PROFILE_IMAGE, false); final boolean display_name = mPreferences.getBoolean(PREFERENCE_KEY_DISPLAY_NAME, true); final boolean force_ssl_connection = mPreferences.getBoolean(PREFERENCE_KEY_FORCE_SSL_CONNECTION, false); mAdapter.setForceSSLConnection(force_ssl_connection); mAdapter.setDisplayProfileImage(display_profile_image); mAdapter.setDisplayHiResProfileImage(hires_profile_image); mAdapter.setDisplayName(display_name); mAdapter.setTextSize(text_size); } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { final boolean reached = firstVisibleItem + visibleItemCount >= totalItemCount && totalItemCount >= visibleItemCount; if (mReachedBottom != reached) { mReachedBottom = reached; if (mReachedBottom && mNotReachedBottomBefore) { mNotReachedBottomBefore = false; return; } } } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { switch (scrollState) { case SCROLL_STATE_FLING: case SCROLL_STATE_TOUCH_SCROLL: mBusy = true; break; case SCROLL_STATE_IDLE: mBusy = false; break; } } @Override public void onStart() { super.onStart(); mTickerStopped = false; mHandler = new Handler(); mTicker = new Runnable() { @Override public void run() { if (mTickerStopped) return; if (mListView != null && !mBusy) { mAdapter.notifyDataSetChanged(); } final long now = SystemClock.uptimeMillis(); final long next = now + TICKER_DURATION - now % TICKER_DURATION; mHandler.postAtTime(mTicker, next); } }; mTicker.run(); setSupportProgressBarIndeterminateVisibility( mService.isReceivedDirectMessagesRefreshing() || mService.isSentDirectMessagesRefreshing()); final IntentFilter filter = new IntentFilter(BROADCAST_REFRESHSTATE_CHANGED); filter.addAction(BROADCAST_RECEIVED_DIRECT_MESSAGES_DATABASE_UPDATED); filter.addAction(BROADCAST_SENT_DIRECT_MESSAGES_DATABASE_UPDATED); registerReceiver(mStatusReceiver, filter); } @Override public void onStop() { unregisterReceiver(mStatusReceiver); mTickerStopped = true; super.onStop(); } @Override protected void onSaveInstanceState(Bundle outState) { outState.putLong(INTENT_KEY_ACCOUNT_ID, mAccountId); outState.putBundle(INTENT_KEY_DATA, mArguments); super.onSaveInstanceState(outState); } private boolean isDualPaneMode() { return findViewById(PANE_LEFT) instanceof ViewGroup && findViewById(PANE_RIGHT) instanceof ViewGroup; } private void openDirectMessagesConversation(long account_id, long conversation_id) { if (isDualPaneMode()) { if (mDetailsFragment == null) { mDetailsFragment = new DirectMessagesConversationFragment(); } if (mDetailsFragment.isAdded()) { mDetailsFragment.showConversation(account_id, conversation_id); } else { final Bundle args = new Bundle(); args.putLong(INTENT_KEY_ACCOUNT_ID, account_id); args.putLong(INTENT_KEY_CONVERSATION_ID, conversation_id); mDetailsFragment.setArguments(args); final FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.replace(PANE_RIGHT, mDetailsFragment); ft.addToBackStack(null); ft.setTransitionStyle(FragmentTransaction.TRANSIT_FRAGMENT_FADE); ft.commit(); } } else { final Uri.Builder builder = new Uri.Builder(); builder.scheme(SCHEME_TWIDERE); builder.authority(AUTHORITY_DIRECT_MESSAGES_CONVERSATION); builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id)); builder.appendQueryParameter(QUERY_PARAM_CONVERSATION_ID, String.valueOf(conversation_id)); startActivity(new Intent(Intent.ACTION_VIEW, builder.build())); } } private static class AccountsAdapter extends SimpleCursorAdapter { public AccountsAdapter(Context context) { super(context, R.layout.spinner_item, null, new String[] { Accounts.USERNAME }, new int[] { android.R.id.text1 }, 0); setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); } } }