org.runnerup.view.MainLayout.java Source code

Java tutorial

Introduction

Here is the source code for org.runnerup.view.MainLayout.java

Source

/*
 * Copyright (C) 2012 - 2013 jonas.oreland@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.runnerup.view;

import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Service;
import android.app.TabActivity;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.design.widget.Snackbar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.WebView;
import android.widget.TabHost;
import android.widget.Toast;

import org.runnerup.R;
import org.runnerup.common.util.Constants.DB;
import org.runnerup.db.DBHelper;
import org.runnerup.util.FileUtil;
import org.runnerup.util.Formatter;
import org.runnerup.widget.WidgetUtil;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

@TargetApi(Build.VERSION_CODES.FROYO)
public class MainLayout extends TabActivity implements ActivityCompat.OnRequestPermissionsResultCallback {

    private Drawable myGetDrawable(int resId) {
        Drawable d = getResources().getDrawable(resId);
        return d;
    }

    private enum UpgradeState {
        UNKNOWN, NEW, UPGRADE, DOWNGRADE, SAME
    }

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        setContentView(R.layout.main);

        int versionCode = 0;
        UpgradeState upgradeState = UpgradeState.UNKNOWN;
        SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
        Editor editor = pref.edit();
        try {
            PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
            versionCode = pInfo.versionCode;
            int version = pref.getInt("app-version", -1);
            if (version == -1) {
                upgradeState = UpgradeState.NEW;
            } else if (versionCode == version) {
                upgradeState = UpgradeState.SAME;
            } else if (versionCode > version) {
                upgradeState = UpgradeState.UPGRADE;
            } else if (versionCode < version) {
                upgradeState = UpgradeState.DOWNGRADE;
            }
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }
        editor.putInt("app-version", versionCode);
        boolean km = Formatter.getUseKilometers(getResources(), pref, editor);

        if (upgradeState == UpgradeState.NEW) {
            editor.putString(getResources().getString(R.string.pref_autolap),
                    Double.toString(km ? Formatter.km_meters : Formatter.mi_meters));
        }
        editor.commit();

        // clear basicTargetType between application startup/shutdown
        pref.edit().remove(getString(R.string.pref_basic_target_type)).commit();

        Log.e(getClass().getName(),
                "app-version: " + versionCode + ", upgradeState: " + upgradeState + ", km: " + km);

        // convert pref_mute to pref_mute_bool
        Resources res = getResources();
        try {
            if (pref.contains(res.getString(R.string.pref_mute))) {
                String v = pref.getString(res.getString(R.string.pref_mute), "no");
                editor.putBoolean(res.getString(R.string.pref_mute_bool), v.equalsIgnoreCase("yes"));
                editor.remove(res.getString(R.string.pref_mute));
                editor.commit();
            }
        } catch (Exception e) {
        }

        PreferenceManager.setDefaultValues(this, R.xml.settings, false);
        PreferenceManager.setDefaultValues(this, R.xml.audio_cue_settings, true);

        TabHost tabHost = getTabHost(); // The activity TabHost

        tabHost.addTab(tabHost.newTabSpec("Start")
                .setIndicator(getString(R.string.Start), myGetDrawable(R.drawable.ic_tab_main))
                .setContent(new Intent(this, StartActivity.class)));

        tabHost.addTab(tabHost.newTabSpec("Feed")
                .setIndicator(getString(R.string.feed), myGetDrawable(R.drawable.ic_tab_feed))
                .setContent(new Intent(this, FeedActivity.class)));

        tabHost.addTab(tabHost.newTabSpec("History")
                .setIndicator(getString(R.string.History), myGetDrawable(R.drawable.ic_tab_history))
                .setContent(new Intent(this, HistoryActivity.class)));

        tabHost.addTab(tabHost.newTabSpec("Settings")
                .setIndicator(getString(R.string.Settings), myGetDrawable(R.drawable.ic_tab_setup))
                .setContent(new Intent(this, SettingsActivity.class)));

        tabHost.setCurrentTab(0);
        WidgetUtil.addLegacyOverflowButton(getWindow());

        if (upgradeState == UpgradeState.UPGRADE) {
            whatsNew();
        }
        //GPS is essential, always nag user if not granted
        requestGpsPermissions(this, tabHost.getCurrentView());

        //Import workouts/schemes. No permission needed
        handleBundled(getApplicationContext().getAssets(), "bundled", getFilesDir().getPath() + "/..");

        // if we were called from an intent-filter because user opened "runnerup.db.export", load it
        final Uri data = getIntent().getData();
        if (data != null) {
            if (SettingsActivity.requestReadStoragePermissions(MainLayout.this)) {
                String filePath = null;
                if ("content".equals(data.getScheme())) {
                    Cursor cursor = this.getContentResolver().query(data,
                            new String[] { android.provider.MediaStore.Images.ImageColumns.DATA }, null, null,
                            null);
                    cursor.moveToFirst();
                    filePath = cursor.getString(0);
                    cursor.close();
                } else {
                    filePath = data.getPath();
                }
                Log.i(getClass().getSimpleName(), "Importing database from " + filePath);
                DBHelper.importDatabase(MainLayout.this, filePath);
            } else {
                Toast.makeText(this, "Storage permission not granted in Android settings, db is not imported.",
                        Toast.LENGTH_SHORT).show();
            }
        }
    }

    void handleBundled(AssetManager mgr, String srcBase, String dstBase) {
        String list[] = null;

        try {
            list = mgr.list(srcBase);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (list != null) {
            for (String add : list) {
                boolean isFile = false;

                String src = srcBase + File.separator + add;
                String dst = dstBase + File.separator + add;
                try {
                    InputStream is = mgr.open(src);
                    is.close();
                    isFile = true;
                } catch (Exception ex) {
                    //Normal, src is directory for first call
                }

                Log.v(getClass().getName(), "Found: " + src + ", " + dst + ", isFile: " + isFile);

                if (!isFile) {
                    //The request is hierarchical, source is still on a directory level
                    File dstDir = new File(dstBase);
                    dstDir.mkdir();
                    if (!dstDir.isDirectory()) {
                        Log.w(getClass().getName(),
                                "Failed to copy " + src + " as \"" + dstBase + "\" is not a directory!");
                        continue;
                    }
                    handleBundled(mgr, src, dst);
                } else {
                    //Source is a file, ready to copy
                    File dstFile = new File(dst);
                    if (dstFile.isDirectory() || dstFile.isFile()) {
                        Log.v(getClass().getName(), "Skip: " + dst + ", isDirectory(): " + dstFile.isDirectory()
                                + ", isFile(): " + dstFile.isFile());
                        continue;
                    }

                    //Only copy if the key do not exist already
                    String key = "install_bundled_" + add;
                    SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
                    if (pref.contains(key)) {
                        Log.v(getClass().getName(), "Skip already existing pref: " + key);
                        continue;
                    }

                    pref.edit().putBoolean(key, true).commit();

                    Log.v(getClass().getName(), "Copying: " + dst);
                    InputStream input = null;
                    try {
                        input = mgr.open(src);
                        FileUtil.copy(input, dst);
                        handleHooks(add);
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        FileUtil.close(input);
                    }
                }
            }
        }
    }

    private void handleHooks(String key) {
        if (key.contains("_audio_cues.xml")) {
            String name = key.substring(0, key.indexOf("_audio_cues.xml"));

            SQLiteDatabase mDB = DBHelper.getWritableDatabase(this);

            ContentValues tmp = new ContentValues();
            tmp.put(DB.AUDIO_SCHEMES.NAME, name);
            tmp.put(DB.AUDIO_SCHEMES.SORT_ORDER, 0);
            mDB.insert(DB.AUDIO_SCHEMES.TABLE, null, tmp);

            DBHelper.closeDB(mDB);
        }
    }

    public final OnClickListener onRateClick = new OnClickListener() {
        @Override
        public void onClick(View arg0) {
            try {
                Uri uri = Uri.parse("market://details?id=" + getPackageName());
                startActivity(new Intent(Intent.ACTION_VIEW, uri));
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    };

    public void whatsNew() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        LayoutInflater inflater = (LayoutInflater) getSystemService(Service.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.whatsnew, null);
        WebView wv = (WebView) view.findViewById(R.id.web_view1);
        builder.setTitle(getString(R.string.Whats_new));
        builder.setView(view);
        builder.setPositiveButton(getString(R.string.Rate_RunnerUp), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                onRateClick.onClick(null);
            }

        });
        builder.setNegativeButton(getString(R.string.Dismiss), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        builder.show();
        wv.loadUrl("file:///android_asset/changes.html");
    }

    public static void requestGpsPermissions(final Activity activity, final View view) {
        String[] requiredPerms = new String[] { Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION };
        List<String> defaultPerms = new ArrayList<>();
        List<String> shouldPerms = new ArrayList<>();
        for (final String perm : requiredPerms) {
            if (ContextCompat.checkSelfPermission(activity, perm) != PackageManager.PERMISSION_GRANTED) {

                if (ActivityCompat.shouldShowRequestPermissionRationale(activity, perm)) {
                    shouldPerms.add(perm);
                } else {
                    defaultPerms.add(perm);
                }
            }
        }
        if (defaultPerms.size() > 0) {
            // No explanation needed, we can request the permission.
            final String[] perms = new String[defaultPerms.size()];
            defaultPerms.toArray(perms);
            ActivityCompat.requestPermissions(activity, perms, REQUEST_LOCATION);
        }

        if (shouldPerms.size() > 0) {
            //Snackbar, no popup
            final String[] perms = new String[shouldPerms.size()];
            shouldPerms.toArray(perms);
            Snackbar.make(view, "GPS permission is required", Snackbar.LENGTH_INDEFINITE)
                    .setAction(R.string.OK, new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            ActivityCompat.requestPermissions(activity, perms, REQUEST_LOCATION);
                        }
                    }).show();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Intent i = null;
        switch (item.getItemId()) {
        case R.id.menu_accounts:
            i = new Intent(this, AccountListActivity.class);
            break;
        case R.id.menu_workouts:
            i = new Intent(this, ManageWorkoutsActivity.class);
            break;
        case R.id.menu_audio_cues:
            i = new Intent(this, AudioCueSettingsActivity.class);
            break;
        case R.id.menu_settings:
            getTabHost().setCurrentTab(3);
            return true;
        case R.id.menu_rate:
            onRateClick.onClick(null);
            break;
        case R.id.menu_whatsnew:
            whatsNew();
            break;
        }
        if (i != null) {
            startActivity(i);
        }
        return true;
    }

    /**
     * Id to identify a permission request.
     */
    private static final int REQUEST_LOCATION = 1000;

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {

        if (requestCode == REQUEST_LOCATION) {
            // Check if the only required permission has been granted (could react on the response)
            if (grantResults.length >= 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                String s = "Permission response OK: " + grantResults.length;
                Log.v("MainLayout", s);
                //Toast.makeText(MainLayout.this, s, Toast.LENGTH_SHORT).show();
            } else {
                String s = "Location Permission was not granted: ";
                Log.i("MainLayout", s);
                Toast.makeText(MainLayout.this, s, Toast.LENGTH_SHORT).show();
            }

        } else {
            String s = "Unexpected permission request: " + requestCode;
            Log.w("MainLayout", s);
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
}