it.gulch.linuxday.android.activities.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for it.gulch.linuxday.android.activities.MainActivity.java

Source

/*
 * Copyright 2014 Christophe Beyls
 *
 * 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 it.gulch.linuxday.android.activities;

import android.annotation.SuppressLint;
import android.app.SearchManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.SearchView;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import it.gulch.linuxday.android.R;
import it.gulch.linuxday.android.api.LinuxDayApi;
import it.gulch.linuxday.android.constants.ActionConstants;
import it.gulch.linuxday.android.enums.Section;
import it.gulch.linuxday.android.fragments.dialogs.AboutDialogFragment;
import it.gulch.linuxday.android.fragments.dialogs.DownloadScheduleReminderDialogFragment;
import it.gulch.linuxday.android.services.PreferencesService;
import it.gulch.linuxday.android.services.impl.ManagerFactory;
import it.gulch.linuxday.android.tasks.DownloadScheduleAsyncTask;

/**
 * Main entry point of the application. Allows to switch between section fragments and update the database.
 *
 * @author Christophe Beyls
 * @author Paolo Cortis
 */
public class MainActivity extends ActionBarActivity implements ListView.OnItemClickListener {
    private static final long DATABASE_VALIDITY_DURATION = 24L * 60L * 60L * 1000L; // 24h

    private static final long DOWNLOAD_REMINDER_SNOOZE_DURATION = 24L * 60L * 60L * 1000L; // 24h

    private static final String PREF_LAST_DOWNLOAD_REMINDER_TIME = "last_download_reminder_time";

    private static final String STATE_CURRENT_SECTION = "current_section";

    private static final DateFormat LAST_UPDATE_DATE_FORMAT = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
            DateFormat.SHORT, Locale.getDefault());

    private static final String TAG = MainActivity.class.getSimpleName();

    private Section currentSection;

    private DrawerLayout drawerLayout;

    private ActionBarDrawerToggle drawerToggle;

    private View mainMenu;

    private TextView lastUpdateTextView;

    private MainMenuAdapter menuAdapter;

    private PreferencesService preferencesService;

    private MenuItem refreshItem;

    private MenuItem searchMenuItem;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_PROGRESS);
        setContentView(R.layout.main);

        refreshItem = null;

        setupServices();

        setupDrawer();

        restoreCurrentSection(savedInstanceState);
        setupMainMenu();
        updateActionBar();
    }

    private void setupServices() {
        preferencesService = ManagerFactory.getPreferencesService();
    }

    private void setupDrawer() {
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawerLayout.setDrawerShadow(getResources().getDrawable(R.drawable.drawer_shadow), Gravity.LEFT);
        drawerToggle = new DrawerToggle();
        drawerToggle.setDrawerIndicatorEnabled(true);
        drawerLayout.setDrawerListener(drawerToggle);
        // Disable drawerLayout focus to allow trackball navigation.
        // We handle the drawer closing on back press ourselves.
        drawerLayout.setFocusable(false);
    }

    private void restoreCurrentSection(Bundle savedInstanceState) {
        boolean shouldRestoreSession = (savedInstanceState == null);
        if (shouldRestoreSession) {
            currentSection = Section.TRACKS;
            String fragmentClassName = currentSection.getFragmentClassName();
            Fragment f = Fragment.instantiate(this, fragmentClassName);
            getSupportFragmentManager().beginTransaction().add(R.id.content, f, fragmentClassName).commit();
        } else {
            currentSection = Section.values()[savedInstanceState.getInt(STATE_CURRENT_SECTION)];
        }
    }

    private void setupMainMenu() {
        mainMenu = findViewById(R.id.main_menu);
        ListView menuListView = (ListView) findViewById(R.id.main_menu_list);
        LayoutInflater inflater = LayoutInflater.from(this);
        View menuHeaderView = inflater.inflate(R.layout.header_main_menu, null);
        menuListView.addHeaderView(menuHeaderView, null, false);

        LocalBroadcastManager.getInstance(this).registerReceiver(scheduleRefreshedReceiver,
                new IntentFilter(ActionConstants.ACTION_SCHEDULE_REFRESHED));

        menuAdapter = new MainMenuAdapter(inflater);
        menuListView.setAdapter(menuAdapter);
        menuListView.setOnItemClickListener(this);

        // Last update date, below the menu
        lastUpdateTextView = (TextView) findViewById(R.id.last_update);
        updateLastUpdateTime();

        // Ensure the current section is visible in the menu
        menuListView.setSelection(currentSection.ordinal());
    }

    private void updateLastUpdateTime() {
        long lastUpdateTime = preferencesService.getLastUpdateTime(this);

        String lastUpdateTimeAsString;
        if (lastUpdateTime == -1L) {
            lastUpdateTimeAsString = getString(R.string.never);
        } else {
            lastUpdateTimeAsString = LAST_UPDATE_DATE_FORMAT.format(new Date(lastUpdateTime));
        }

        lastUpdateTextView.setText(getString(R.string.last_update, lastUpdateTimeAsString));
    }

    private void updateActionBar() {
        getSupportActionBar()
                .setTitle(drawerLayout.isDrawerOpen(mainMenu) ? R.string.app_name : currentSection.getTitleResId());
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);

        if (drawerLayout.isDrawerOpen(mainMenu)) {
            updateActionBar();
        }
        drawerToggle.syncState();
    }

    @Override
    public void onBackPressed() {
        if (drawerLayout.isDrawerOpen(mainMenu)) {
            drawerLayout.closeDrawer(mainMenu);
        } else {
            super.onBackPressed();
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(STATE_CURRENT_SECTION, currentSection.ordinal());
    }

    @Override
    protected void onStart() {
        super.onStart();

        // Ensure the progress bar is hidden when starting
        //setSupportProgressBarVisibility(false);

        // Monitor the schedule download
        LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
        lbm.registerReceiver(scheduleDownloadProgressReceiver,
                new IntentFilter(LinuxDayApi.ACTION_DOWNLOAD_SCHEDULE_PROGRESS));
        lbm.registerReceiver(scheduleDownloadResultReceiver,
                new IntentFilter(LinuxDayApi.ACTION_DOWNLOAD_SCHEDULE_RESULT));

        // Download reminder
        long now = System.currentTimeMillis();
        long time = preferencesService.getLastUpdateTime(this);
        if ((time == -1L) || (time < (now - DATABASE_VALIDITY_DURATION))) {
            SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
            time = prefs.getLong(PREF_LAST_DOWNLOAD_REMINDER_TIME, -1L);
            if ((time == -1L) || (time < (now - DOWNLOAD_REMINDER_SNOOZE_DURATION))) {
                prefs.edit().putLong(PREF_LAST_DOWNLOAD_REMINDER_TIME, now).commit();

                FragmentManager fm = getSupportFragmentManager();
                if (fm.findFragmentByTag("download_reminder") == null) {
                    new DownloadScheduleReminderDialogFragment().show(fm, "download_reminder");
                }
            }
        }
    }

    @Override
    protected void onStop() {
        if (searchMenuItem != null && MenuItemCompat.isActionViewExpanded(searchMenuItem)) {
            MenuItemCompat.collapseActionView(searchMenuItem);
        }

        LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
        lbm.unregisterReceiver(scheduleDownloadProgressReceiver);
        lbm.unregisterReceiver(scheduleDownloadResultReceiver);

        super.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        LocalBroadcastManager.getInstance(this).unregisterReceiver(scheduleRefreshedReceiver);
    }

    @SuppressLint("NewApi")
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);

        MenuItem searchMenuItem = menu.findItem(R.id.search);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
            this.searchMenuItem = searchMenuItem;
            // Associate searchable configuration with the SearchView
            SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
            SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchMenuItem);
            searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        } else {
            // Legacy search mode for Eclair
            MenuItemCompat.setActionView(searchMenuItem, null);
            MenuItemCompat.setShowAsAction(searchMenuItem, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
        }

        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // Hide & disable primary (contextual) action items when the main menu is opened
        if (drawerLayout.isDrawerOpen(mainMenu)) {
            final int size = menu.size();
            for (int i = 0; i < size; ++i) {
                MenuItem item = menu.getItem(i);
                if ((item.getOrder() & 0xFFFF0000) == 0) {
                    item.setVisible(false).setEnabled(false);
                }
            }
        }

        MenuItem refreshMenuItem = menu.findItem(R.id.refresh);

        boolean isRefreshing = refreshItem != null;
        Log.d(TAG, "isRefreshing: " + Boolean.toString(isRefreshing));
        refreshMenuItem.setEnabled(!isRefreshing);

        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Will close the drawer if the home button is pressed
        if (drawerToggle.onOptionsItemSelected(item)) {
            return true;
        }

        switch (item.getItemId()) {
        case R.id.search:
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
                return false;
            } else {
                // Legacy search mode for Eclair
                onSearchRequested();
                return true;
            }
        case R.id.refresh:
            refreshItem = enableRefreshAnimation(item);
            startDownloadSchedule();
            return true;
        case R.id.settings:
            startActivity(new Intent(this, SettingsActivity.class));
            overridePendingTransition(R.anim.slide_in_right, R.anim.partial_zoom_out);
            return true;
        case R.id.about:
            new AboutDialogFragment().show(getSupportFragmentManager(), "about");
            return true;
        }
        return false;
    }

    @SuppressLint("NewApi")
    public void startDownloadSchedule() {
        // Start by displaying indeterminate progress, determinate will come later
        //setSupportProgressBarIndeterminate(true);
        //setSupportProgressBarVisibility(true);

        DownloadScheduleAsyncTask instance = new DownloadScheduleAsyncTask(this);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            instance.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        } else {
            instance.execute();
        }
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        // Decrease position by 1 since the listView has a header view.
        Section section = menuAdapter.getItem(position - 1);
        if (section != currentSection) {
            // Switch to new section
            FragmentManager fm = getSupportFragmentManager();
            FragmentTransaction ft = fm.beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
            Fragment f = fm.findFragmentById(R.id.content);
            if (f != null) {
                if (currentSection.shouldKeep()) {
                    ft.detach(f);
                } else {
                    ft.remove(f);
                }
            }
            String fragmentClassName = section.getFragmentClassName();
            if (section.shouldKeep() && ((f = fm.findFragmentByTag(fragmentClassName)) != null)) {
                ft.attach(f);
            } else {
                f = Fragment.instantiate(this, fragmentClassName);
                ft.add(R.id.content, f, fragmentClassName);
            }
            ft.commit();

            currentSection = section;
            menuAdapter.notifyDataSetChanged();
        }

        drawerLayout.closeDrawer(mainMenu);
    }

    private MenuItem enableRefreshAnimation(MenuItem refreshItem) {
        LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        ImageView iv = (ImageView) inflater.inflate(R.layout.refresh_action_view, null);

        Animation rotation = AnimationUtils.loadAnimation(this, R.anim.clockwise_refresh);
        rotation.setRepeatCount(Animation.INFINITE);
        iv.startAnimation(rotation);

        return MenuItemCompat.setActionView(refreshItem, iv);
    }

    private void disableRefreshAnimation() {
        if (refreshItem == null) {
            return;
        }

        View actionView = MenuItemCompat.getActionView(refreshItem);
        if (actionView != null) {
            actionView.clearAnimation();
        }

        MenuItemCompat.setActionView(refreshItem, null);
        refreshItem = null;
    }

    // MAIN MENU
    private class MainMenuAdapter extends BaseAdapter {
        private Section[] sections = Section.values();

        private LayoutInflater inflater;

        private int currentSectionBackgroundColor;

        public MainMenuAdapter(LayoutInflater inflater) {
            this.inflater = inflater;
            currentSectionBackgroundColor = getResources().getColor(R.color.translucent_grey);
        }

        @Override
        public int getCount() {
            return sections.length;
        }

        @Override
        public Section getItem(int position) {
            return sections[position];
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = inflater.inflate(R.layout.item_main_menu, parent, false);
            }

            Section section = getItem(position);

            TextView tv = (TextView) convertView.findViewById(R.id.section_text);
            tv.setText(section.getTitleResId());
            tv.setCompoundDrawablesWithIntrinsicBounds(section.getIconResId(), 0, 0, 0);
            // Show highlighted background for current section
            tv.setBackgroundColor((section == currentSection) ? currentSectionBackgroundColor : Color.TRANSPARENT);

            return convertView;
        }
    }

    private final BroadcastReceiver scheduleDownloadProgressReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            //         setSupportProgressBarIndeterminate(false);
            setSupportProgress(intent.getIntExtra(LinuxDayApi.EXTRA_PROGRESS, 0) * 100);
        }
    };

    private final BroadcastReceiver scheduleDownloadResultReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            // Hide the progress bar with a fill and fade out animation
            //setSupportProgressBarIndeterminate(false);
            //setSupportProgress(10000);
            disableRefreshAnimation();
            supportInvalidateOptionsMenu();

            int result = intent.getIntExtra(LinuxDayApi.EXTRA_RESULT, LinuxDayApi.RESULT_ERROR);
            if (result == LinuxDayApi.RESULT_ERROR) {
                Toast.makeText(MainActivity.this, R.string.schedule_loading_error, Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(MainActivity.this, getString(R.string.events_download_completed, result),
                        Toast.LENGTH_LONG).show();
            }
        }
    };

    private final BroadcastReceiver scheduleRefreshedReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            updateLastUpdateTime();
        }
    };

    private class DrawerToggle extends ActionBarDrawerToggle {
        public DrawerToggle() {
            super(MainActivity.this, MainActivity.this.drawerLayout, R.string.main_menu, R.string.close_menu);
        }

        @Override
        public void onDrawerOpened(View drawerView) {
            updateActionBar();
            disableRefreshAnimation();
            supportInvalidateOptionsMenu();
            // Make keypad navigation easier
            mainMenu.requestFocus();
        }

        @Override
        public void onDrawerClosed(View drawerView) {
            updateActionBar();
            disableRefreshAnimation();
            supportInvalidateOptionsMenu();
        }
    }
}