Java tutorial
/* * Copyright (C) 2013 Marten Gajda <marten@dmfs.org> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.granita.tasks; import java.io.IOException; import org.dmfs.android.retentionmagic.annotations.Retain; import com.google.android.gms.analytics.HitBuilders; import com.google.android.gms.analytics.Tracker; import com.granita.installicloud; import com.granita.provider.tasks.TaskContract.Tasks; import com.granita.tasks.groupings.AbstractGroupingFactory; import com.granita.tasks.groupings.ByDueDate; import com.granita.tasks.groupings.ByList; import com.granita.tasks.groupings.ByPriority; import com.granita.tasks.groupings.ByProgress; import com.granita.tasks.groupings.BySearch; import com.granita.tasks.groupings.ByStartDate; import com.granita.tasks.model.ContentSet; import com.granita.tasks.notification.AlarmBroadcastReceiver; import com.granita.tasks.util.IabHelper; import com.granita.tasks.util.IabResult; import com.granita.tasks.util.Inventory; import com.granita.tasks.util.Purchase; import com.granita.tasks.utils.ActionBarActivity; import com.granita.tasks.utils.ExpandableGroupDescriptor; import com.granita.tasks.utils.SearchHistoryHelper; import org.dmfs.xmlobjects.pull.XmlObjectPullParserException; import org.xmlpull.v1.XmlPullParserException; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.SearchManager; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.os.Build; import android.os.Build.VERSION; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.view.MenuItemCompat; import android.support.v4.view.MenuItemCompat.OnActionExpandListener; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.support.v7.app.AlertDialog; import android.support.v7.widget.SearchView; import android.support.v7.widget.SearchView.OnQueryTextListener; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.Button; import com.astuetz.PagerSlidingTabStrip; /** * An activity representing a list of Tasks. This activity has different presentations for handset and tablet-size devices. On handsets, the activity presents a * list of items, which when touched, lead to a {@link ViewTaskActivity} representing item details. On tablets, the activity presents the list of items and item * details side-by-side using two vertical panes. * <p> * The activity makes heavy use of fragments. The list of items is a {@link TaskListFragment} and the item details (if present) is a {@link ViewTaskFragment}. * <p> * This activity also implements the required {@link TaskListFragment.Callbacks} interface to listen for item selections. * * <p> * TODO: move the code to persist the expanded groups into a the GroupingDescriptor class * </p> * * @author Tobias Reinsch <tobias@dmfs.org> */ public class TaskListActivity extends ActionBarActivity implements TaskListFragment.Callbacks, ViewTaskFragment.Callback { /** Tells the activity to display the details of the task with the URI from the intent data. **/ public static final String EXTRA_DISPLAY_TASK = "com.granita.tasks.DISPLAY_TASK"; /** Tells the activity to select the task in the list with the URI from the intent data. **/ public static final String EXTRA_FORCE_LIST_SELECTION = "com.granita.tasks.FORCE_LIST_SELECTION"; private static final String TAG = "TaskListActivity"; private final static int REQUEST_CODE_NEW_TASK = 2924; /** * The time to wait for a new key before updating the search view. */ private final static int SEARCH_UPDATE_DELAY = 400; // ms private final static String DETAIL_FRAGMENT_TAG = "taskListActivity.ViewTaskFragment"; /** * Array of {@link ExpandableGroupDescriptor}s. */ private AbstractGroupingFactory[] mGroupingFactories; /** * Whether or not the activity is in two-pane mode, i.e. running on a tablet device. */ private boolean mTwoPane; private ViewTaskFragment mTaskDetailFrag; private ViewPager mViewPager; private TaskGroupPagerAdapter mPagerAdapter; @Retain(permanent = true) private int mCurrentPageId; /** The current pager position **/ private int mCurrentPagePosition = 0; private int mPreviousPagePosition = -1; private String mAuthority; private MenuItem mSearchItem; private PagerSlidingTabStrip mTabs; private final Handler mHandler = new Handler(); private SearchHistoryHelper mSearchHistoryHelper; private boolean mAutoExpandSearchView = false; /** Indicates that the activity switched to detail view due to rotation. **/ @Retain private boolean mSwitchedToDetail = false; /** The Uri of the task to display/highlight in the list view. **/ @Retain private Uri mSelectedTaskUri; /** The Uri of the task to display/highlight in the list view coming from the widget. **/ private Uri mSelectedTaskUriOnLaunch; /** Indicates to display the two pane layout with details **/ @Retain private boolean mShouldShowDetails = false; /** Indicates to show ViewTaskActivity when rotating to single pane. **/ @Retain private boolean mShouldSwitchToDetail = false; /** Indicates the TaskListFragments to select/highlight the mSelectedTaskUri item **/ private boolean mShouldSelectTaskListItem = false; /** Indicates a transient state after rotation to redirect to the TaskViewActivtiy **/ private boolean mTransientState = false; //Custom start IabHelper mHelper; static final String ITEM_SKU = "com.granita.tasks"; //static final String ITEM_SKU = "android.test.purchased"; boolean mIsPremium = false; IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() { public void onQueryInventoryFinished(IabResult result, Inventory inventory) { if (result.isFailure()) { // handle error here } else { // does the user have the premium upgrade? mIsPremium = inventory.hasPurchase(ITEM_SKU); if (mIsPremium) { SharedPreferences sharedPref = getSharedPreferences("localPreferences", Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPref.edit(); editor.putBoolean(getString(R.string.HIDE_AD_BOOLEAN), true); editor.commit(); View adFragmentView = findViewById(R.id.fragment2); adFragmentView.setVisibility(View.GONE); } else { SharedPreferences sharedPref = getSharedPreferences("localPreferences", Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPref.edit(); editor.putBoolean(getString(R.string.HIDE_AD_BOOLEAN), false); editor.commit(); } } } }; IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() { public void onIabPurchaseFinished(IabResult result, Purchase purchase) { if (result.isFailure()) { // Handle error return; } else if (purchase.getSku().equals(ITEM_SKU)) { SharedPreferences sharedPref = getSharedPreferences("localPreferences", Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPref.edit(); editor.putBoolean(getString(R.string.HIDE_AD_BOOLEAN), true); editor.commit(); View adFragmentView = findViewById(R.id.fragment2); adFragmentView.setVisibility(View.GONE); } } }; @Override public void onStart() { super.onStart(); final SharedPreferences settings = getSharedPreferences("localPreferences", MODE_PRIVATE); if (settings.getBoolean("isFirstRun", true)) { new AlertDialog.Builder(this).setTitle("Cookies").setMessage( "We use device identifiers to personalise content and ads, to provide social media features and to analyse our traffic. We also share such identifiers and other information from your device with our social media, advertising and analytics partners.") .setNeutralButton("Close message", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { settings.edit().putBoolean("isFirstRun", false).commit(); } }).show(); } } //Custom end @SuppressLint("NewApi") @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override protected void onCreate(Bundle savedInstanceState) { Log.d(TAG, "onCreate called again"); super.onCreate(savedInstanceState); // check for single pane activity change mTwoPane = getResources().getBoolean(R.bool.has_two_panes); resolveIntentAction(getIntent()); //custom start Tracker t = ((com.granita.tasks.Tasks) getApplication()) .getTracker(com.granita.tasks.Tasks.TrackerName.APP_TRACKER); t.setScreenName("Tasks: List activity"); t.send(new HitBuilders.AppViewBuilder().build()); //check if sync for icloud calendar exists String packageName = "com.granita.caldavsync"; Intent intent = this.getPackageManager().getLaunchIntentForPackage(packageName); if (intent == null) { /* bring user to the market or let them choose an app? */ intent = new Intent(this, installicloud.class); startActivity(intent); } try { //Start premium features String base64EncodedPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvczcgR9FJqJ/LK94t4VcmdfVizoy66QWJRxF+o0ZZbFeMi1jQ6kBcYb1kogQnLLBeS+Q0DtRjsxap9Z6B8yP5rcZxIs51yF2LKy9+nmcLeJF0wPU2cvIjZLf7dD7Umh/LMi88VHSLExwkDMb2vBpcROz7DwjhgF5fzXHWh986ZxWmJiMiYLX1cg5toWaOPYgxcSELyCsfkvfmtX8ctJ+QcovWXevSBJsOQCLNkmKdBd5biExy96WicjVUZ/e31/CCjb8xYcMJnMaBGXEBDdtJFMFAczpdrB+Zyw6gEr1ZUH1U7trsbTrC2TvOa1MTcwXHE2JwqjU2eke4FLYIcAdbwIDAQAB"; mHelper = new IabHelper(this, base64EncodedPublicKey); mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { public void onIabSetupFinished(IabResult result) { if (!result.isSuccess()) { Log.d(TAG, "In-app Billing setup failed: " + result); } else { mHelper.queryInventoryAsync(mGotInventoryListener); Log.d(TAG, "In-app Billing is set up OK"); } } }); //End premium features } catch (Exception e) { } //custom end if (mSelectedTaskUri != null) { if (mShouldShowDetails && mShouldSwitchToDetail) { Intent viewTaskIntent = new Intent(Intent.ACTION_VIEW); viewTaskIntent.setData(mSelectedTaskUri); startActivity(viewTaskIntent); mSwitchedToDetail = true; mShouldSwitchToDetail = false; mTransientState = true; } } else { mShouldShowDetails = false; } setContentView(R.layout.activity_task_list); //custom start mAuthority = getString(R.string.org_dmfs_tasks_authority); //custom end mSearchHistoryHelper = new SearchHistoryHelper(this); if (findViewById(R.id.task_detail_container) != null) { // In two-pane mode, list items should be given the // 'activated' state when touched. // get list fragment // mTaskListFrag = (TaskListFragment) getSupportFragmentManager().findFragmentById(R.id.task_list); // mTaskListFrag.setListViewScrollbarPositionLeft(true); // mTaskListFrag.setActivateOnItemClick(true); /* * Create a detail fragment, but don't load any URL yet, we do that later when the fragment gets attached */ mTaskDetailFrag = ViewTaskFragment.newInstance(mSelectedTaskUri); getSupportFragmentManager().beginTransaction() .replace(R.id.task_detail_container, mTaskDetailFrag, DETAIL_FRAGMENT_TAG).commit(); } else { FragmentManager fragmentManager = getSupportFragmentManager(); Fragment detailFragment = fragmentManager.findFragmentByTag(DETAIL_FRAGMENT_TAG); if (detailFragment != null) { fragmentManager.beginTransaction().remove(detailFragment).commit(); } } mGroupingFactories = new AbstractGroupingFactory[] { new ByList(mAuthority), new ByDueDate(mAuthority), new ByStartDate(mAuthority), new ByPriority(mAuthority), new ByProgress(mAuthority), new BySearch(mAuthority, mSearchHistoryHelper) }; // set up pager adapter try { mPagerAdapter = new TaskGroupPagerAdapter(getSupportFragmentManager(), mGroupingFactories, this, R.xml.listview_tabs); } catch (XmlPullParserException e) { // TODO Automatisch generierter Erfassungsblock e.printStackTrace(); } catch (IOException e) { // TODO Automatisch generierter Erfassungsblock e.printStackTrace(); } catch (XmlObjectPullParserException e) { // TODO Automatisch generierter Erfassungsblock e.printStackTrace(); } // Setup ViewPager mPagerAdapter.setTwoPaneLayout(mTwoPane); mViewPager = (ViewPager) findViewById(R.id.pager); mViewPager.setAdapter(mPagerAdapter); int currentPageIndex = mPagerAdapter.getPagePosition(mCurrentPageId); if (currentPageIndex >= 0) { mCurrentPagePosition = currentPageIndex; mViewPager.setCurrentItem(currentPageIndex); if (VERSION.SDK_INT >= 14 && mCurrentPageId == R.id.task_group_search) { if (mSearchItem != null) { // that's actually quite impossible to happen MenuItemCompat.expandActionView(mSearchItem); } else { mAutoExpandSearchView = true; } } } updateTitle(currentPageIndex); // Bind the tabs to the ViewPager mTabs = (PagerSlidingTabStrip) findViewById(R.id.tabs); mTabs.setViewPager(mViewPager); mTabs.setOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageSelected(int position) { mSelectedTaskUri = null; mCurrentPagePosition = position; int newPageId = mPagerAdapter.getPageId(position); if (newPageId == R.id.task_group_search) { int oldPageId = mCurrentPageId; mCurrentPageId = newPageId; // store the page position we're coming from mPreviousPagePosition = mPagerAdapter.getPagePosition(oldPageId); } else if (mCurrentPageId == R.id.task_group_search) { // we've been on the search page before, so commit the search and close the search view mSearchHistoryHelper.commitSearch(); mHandler.post(mSearchUpdater); mCurrentPageId = newPageId; hideSearchActionView(); } mCurrentPageId = newPageId; updateTitle(mCurrentPageId); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageScrollStateChanged(int state) { if (state == ViewPager.SCROLL_STATE_IDLE && mCurrentPageId == R.id.task_group_search) { // the search page is selected now, expand the search view mHandler.post(new Runnable() { @Override public void run() { MenuItemCompat.expandActionView(mSearchItem); } }); } } }); // make sure the status bar color is set properly on Android 5+ devices if (VERSION.SDK_INT >= 21) { Window window = getWindow(); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(getResources().getColor(R.color.colorPrimaryDarker)); } } @Override protected void onResume() { updateTitle(mCurrentPageId); super.onResume(); } @Override protected void onNewIntent(Intent intent) { resolveIntentAction(intent); super.onNewIntent(intent); } @Override protected void onDestroy() { super.onDestroy(); mSearchHistoryHelper.close(); //custom start if (mHelper != null) mHelper.dispose(); mHelper = null; //custom end } /** * Callback method from {@link TaskListFragment.Callbacks} indicating that the item with the given ID was selected. */ @Override public void onItemSelected(Uri uri, boolean forceReload, int pagePosition) { // only accept selections from the current visible task fragment or the activity itself if (pagePosition == -1 || pagePosition == mCurrentPagePosition) { if (mTwoPane) { mShouldShowDetails = true; if (forceReload) { mSelectedTaskUri = null; mShouldSwitchToDetail = false; mTaskDetailFrag.loadUri(uri); } else { mTaskDetailFrag.loadUri(uri); } } else if (forceReload) { mSelectedTaskUri = uri; // In single-pane mode, simply start the detail activity // for the selected item ID. Intent detailIntent = new Intent(Intent.ACTION_VIEW); detailIntent.setData(uri); startActivity(detailIntent); mSwitchedToDetail = true; mShouldSwitchToDetail = false; } } } private void updateTitle(int pageId) { switch (pageId) { case R.id.task_group_by_list: setTitle(R.string.task_group_title_list); break; case R.id.task_group_by_start: setTitle(R.string.task_group_title_start); break; case R.id.task_group_by_due: setTitle(R.string.task_group_title_due); break; case R.id.task_group_by_priority: setTitle(R.string.task_group_title_priority); break; case R.id.task_group_by_progress: setTitle(R.string.task_group_title_progress); break; default: setTitle(R.string.task_group_title_default); break; } } @Override public void onEditTask(Uri taskUri, ContentSet data) { Intent editTaskIntent = new Intent(Intent.ACTION_EDIT); editTaskIntent.setData(taskUri); if (data != null) { editTaskIntent.putExtra(EditTaskActivity.EXTRA_DATA_CONTENT_SET, data); } startActivity(editTaskIntent); } @Override public void onAddNewTask() { Intent editTaskIntent = new Intent(Intent.ACTION_INSERT); editTaskIntent.setData(Tasks.getContentUri(mAuthority)); startActivityForResult(editTaskIntent, REQUEST_CODE_NEW_TASK); } private void resolveIntentAction(Intent intent) { // check which task should be selected if (intent.hasExtra(EXTRA_DISPLAY_TASK)) { mShouldSwitchToDetail = true; mSelectedTaskUri = intent.getData(); } if (intent != null && intent.hasExtra(EXTRA_DISPLAY_TASK) && intent.getBooleanExtra(EXTRA_FORCE_LIST_SELECTION, true) && mTwoPane) { mShouldSwitchToDetail = true; Uri newSelection = intent.getData(); mSelectedTaskUriOnLaunch = newSelection; mShouldSelectTaskListItem = true; mPagerAdapter.notifyDataSetChanged(); } else { mSelectedTaskUriOnLaunch = null; mShouldSelectTaskListItem = false; } } @Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { if (resultCode == RESULT_OK) { if (intent != null) { Uri taskUri = intent.getData(); if (taskUri != null) { // select the new task onItemSelected(taskUri, false, -1); } } } } @Override public void onDelete(Uri taskUri) { // nothing to do here, the loader will take care of reloading the list and the list view will take care of selecting the next element. // empty the detail fragment if (mTwoPane) { mTaskDetailFrag.loadUri(null); } } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.task_list_activity_menu, menu); // restore menu state MenuItem item = menu.findItem(R.id.menu_alarms); if (item != null) { item.setChecked(AlarmBroadcastReceiver.getAlarmPreference(this)); } // search setupSearch(menu); //customs start SharedPreferences sharedPref = getSharedPreferences("localPreferences", Context.MODE_PRIVATE); if (sharedPref.getBoolean(getString(R.string.HIDE_AD_BOOLEAN), false)) { //remove all ads MenuItem removeAdItem = menu.findItem(R.id.removeads); removeAdItem.setVisible(false); } else { MenuItem removeAdItem = menu.findItem(R.id.removeads); removeAdItem.setVisible(true); } //custom end return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { //custom start if (item.getItemId() == R.id.removeads) { mHelper.launchPurchaseFlow(this, ITEM_SKU, 10001, mPurchaseFinishedListener, "mypurchasetoken"); } if (item.getItemId() == R.id.add_account) { Intent myIntent = new Intent(); myIntent.setClassName("com.granita.icloudcalsync", "com.granita.caldavsync.ui.setup.AddAccountActivity"); startActivity(myIntent); } //custom end if (item.getItemId() == R.id.menu_visible_list) { Intent settingsIntent = new Intent(getBaseContext(), SyncSettingsActivity.class); startActivity(settingsIntent); return true; } else if (item.getItemId() == R.id.menu_alarms) { // set and save state boolean activatedAlarms = !item.isChecked(); item.setChecked(activatedAlarms); AlarmBroadcastReceiver.setAlarmPreference(this, activatedAlarms); return true; } else { return super.onOptionsItemSelected(item); } } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) private void hideSearchActionView() { MenuItemCompat.collapseActionView(mSearchItem); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public void setupSearch(Menu menu) { // bail early on unsupported devices if (Build.VERSION.SDK_INT < 11) { return; } mSearchItem = menu.findItem(R.id.search); MenuItemCompat.setOnActionExpandListener(mSearchItem, new OnActionExpandListener() { @Override public boolean onMenuItemActionExpand(MenuItem item) { // always allow expansion of the search action view return mCurrentPageId == R.id.task_group_search; } @Override public boolean onMenuItemActionCollapse(MenuItem item) { // return to previous view if (mPreviousPagePosition >= 0 && mCurrentPageId == R.id.task_group_search) { mViewPager.setCurrentItem(mPreviousPagePosition); mCurrentPageId = mPagerAdapter.getPageId(mPreviousPagePosition); } return mPreviousPagePosition >= 0 || mCurrentPageId != R.id.task_group_search; } }); SearchView searchView = (SearchView) MenuItemCompat.getActionView(mSearchItem); SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); if (null != searchManager) { searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName())); } searchView.setQueryHint(getString(R.string.menu_search_hint)); searchView.setIconified(true); searchView.setOnQueryTextListener(new OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { // persist current search mSearchHistoryHelper.commitSearch(); mHandler.post(mSearchUpdater); return true; } @Override public boolean onQueryTextChange(String query) { if (mCurrentPageId != R.id.task_group_search) { return true; } mHandler.removeCallbacks(mSearchUpdater); if (query.length() > 0) { mSearchHistoryHelper.updateSearch(query); mHandler.postDelayed(mSearchUpdater, SEARCH_UPDATE_DELAY); } else { mSearchHistoryHelper.removeCurrentSearch(); mHandler.post(mSearchUpdater); } return true; } }); if (mAutoExpandSearchView) { mSearchItem.expandActionView(); } } @Override public ExpandableGroupDescriptor getGroupDescriptor(int pageId) { for (AbstractGroupingFactory factory : mGroupingFactories) { if (factory.getId() == pageId) { return factory.getExpandableGroupDescriptor(); } } return null; } /** * Notifies the search fragment of an update. */ private final Runnable mSearchUpdater = new Runnable() { @Override public void run() { TaskListFragment fragment = (TaskListFragment) mPagerAdapter.instantiateItem(mViewPager, mViewPager.getCurrentItem()); fragment.notifyDataSetChanged(true); fragment.expandCurrentSearchGroup(); } }; @SuppressLint("NewApi") @Override public void updateColor(int color) { getSupportActionBar().setBackgroundDrawable(new ColorDrawable(color)); mTabs.setBackgroundColor(color); if (VERSION.SDK_INT >= 21) { Window window = getWindow(); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(color); } } public Uri getSelectedTaskUri() { if (mShouldSelectTaskListItem) { return mSelectedTaskUriOnLaunch; } return null; } public boolean isInTransientState() { return mTransientState; } }