org.LK8000.LK8000.java Source code

Java tutorial

Introduction

Here is the source code for org.LK8000.LK8000.java

Source

/* Copyright_License {
    
  XCSoar Glide Computer - http://www.xcsoar.org/
  Copyright (C) 2000-2016 The XCSoar Project
  A detailed list of copyright holders can be found in the file "AUTHORS".
    
  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 2
  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, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
}
*/

package org.LK8000;

import android.Manifest;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.KeyEvent;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
import android.os.Build;
import android.os.Environment;
import android.os.PowerManager;
import android.os.Handler;
import android.os.Message;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import android.provider.Settings;
import com.crashlytics.android.Crashlytics;
import com.crashlytics.android.ndk.CrashlyticsNdk;

import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import io.fabric.sdk.android.Fabric;

public class LK8000 extends Activity {
    private static final String TAG = "LK8000";

    /**
     * Hack: this is set by onCreate(), to support the "testing"
     * package.
     */
    protected static Class<?> serviceClass;
    private static NativeView nativeView;

    PowerManager.WakeLock wakeLock;

    BatteryReceiver batteryReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        if (serviceClass == null)
            serviceClass = MyService.class;

        super.onCreate(savedInstanceState);
        //    Fabric.with(this, new Crashlytics(), new CrashlyticsNdk());

        Fabric fabric = new Fabric.Builder(this).debuggable(true).kits(new Crashlytics(), new CrashlyticsNdk())
                .build();

        Fabric.with(fabric);

        Log.d(TAG, "ABI=" + Build.CPU_ABI);
        Log.d(TAG, "PRODUCT=" + Build.PRODUCT);
        Log.d(TAG, "MANUFACTURER=" + Build.MANUFACTURER);
        Log.d(TAG, "MODEL=" + Build.MODEL);
        Log.d(TAG, "DEVICE=" + Build.DEVICE);
        Log.d(TAG, "BOARD=" + Build.BOARD);
        Log.d(TAG, "FINGERPRINT=" + Build.FINGERPRINT);

        if (!Loader.loaded) {
            TextView tv = new TextView(this);
            tv.setText("Failed to load the native LK8000 libary.\n"
                    + "Report this problem to us, and include the following information:\n" + "ABI=" + Build.CPU_ABI
                    + "\n" + "PRODUCT=" + Build.PRODUCT + "\n" + "FINGERPRINT=" + Build.FINGERPRINT + "\n"
                    + "error=" + Loader.error);
            setContentView(tv);
            return;
        }

        initialiseNative();

        NetUtil.initialise(this);
        InternalGPS.Initialize();
        NonGPSSensors.Initialize();

        IOIOHelper.onCreateContext(this);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR)
            // Bluetooth suppoert was added in Android 2.0 "Eclair"
            BluetoothHelper.Initialize(this);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD)
            // the DownloadManager was added in Android 2.3 "Gingerbread"
            DownloadUtil.Initialise(getApplicationContext());

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
            UsbSerialHelper.Initialise(this);
        }

        SoundUtil.Initialise();

        // fullscreen mode
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().addFlags(
                WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        /* Workaround for layout problems in Android KitKat with immersive full
           screen mode: Sometimes the content view was not initialized with the
           correct size, which caused graphics artifacts. */
        if (android.os.Build.VERSION.SDK_INT >= 19) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                    | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
                    | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
        }

        enableImmersiveModeIfSupported();

        TextView tv = new TextView(this);
        tv.setText("Loading LK8000...");
        setContentView(tv);

        batteryReceiver = new BatteryReceiver();
        registerReceiver(batteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

        SharedPreferences settings = getSharedPreferences("LK8000", 0);
        int screenOrientation = settings.getInt("screenOrientation", 0);
        switch (screenOrientation) {
        case 0:
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
            break;
        case 1:
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            break;
        case 2:
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            break;
        case 3:
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
            break;
        case 4:
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
            break;
        default:
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
        }

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

    }

    private void quit() {
        Log.d(TAG, "in quit()");

        nativeView = null;

        Log.d(TAG, "stopping service");
        stopService(new Intent(this, serviceClass));

        TextView tv = new TextView(LK8000.this);
        tv.setText("Shutting down LK8000...");
        setContentView(tv);

        Log.d(TAG, "finish()");
        finish();
    }

    final Handler quitHandler = new Handler() {
        public void handleMessage(Message msg) {
            quit();
        }
    };

    final Handler errorHandler = new Handler() {
        public void handleMessage(Message msg) {
            nativeView = null;
            TextView tv = new TextView(LK8000.this);
            tv.setText(msg.obj.toString());
            setContentView(tv);

        }
    };

    public void initSDL() {
        if (!Loader.loaded)
            return;

        /* check if external storage is available; LK8000 doesn't work as
           long as external storage is being forwarded to a PC */
        String state = Environment.getExternalStorageState();
        Log.d(TAG, "getExternalStorageState() = " + state);
        if (!Environment.MEDIA_MOUNTED.equals(state)) {
            TextView tv = new TextView(this);
            tv.setText("External storage is not available (state='" + state + "').  Please turn off USB storage.");
            setContentView(tv);
            return;
        }

        nativeView = new NativeView(this, quitHandler, errorHandler);
        setContentView(nativeView);
        // Receive keyboard events
        nativeView.setFocusableInTouchMode(true);
        nativeView.setFocusable(true);
        nativeView.requestFocus();

        // Obtain an instance of the Android PowerManager class
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);

        // Create a WakeLock instance to keep the screen from timing out
        final String LKTAG = "LK8000:" + BuildConfig.BUILD_TYPE;
        wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, LKTAG);

        // Activate the WakeLock
        wakeLock.acquire();
    }

    @Override
    protected void onPause() {
        if (nativeView != null)
            nativeView.onPause();
        super.onPause();
    }

    private void getHapticFeedbackSettings() {
        boolean hapticFeedbackEnabled;
        try {
            hapticFeedbackEnabled = (Settings.System.getInt(getContentResolver(),
                    Settings.System.HAPTIC_FEEDBACK_ENABLED)) != 0;
        } catch (Settings.SettingNotFoundException e) {
            hapticFeedbackEnabled = false;
        }

        if (nativeView != null)
            nativeView.setHapticFeedback(hapticFeedbackEnabled);
    }

    private void enableImmersiveModeIfSupported() {
        // Set / Reset the System UI visibility flags for Immersive Full Screen Mode, if supported
        if (android.os.Build.VERSION.SDK_INT >= 19)
            ImmersiveFullScreenMode.enable(getWindow().getDecorView());
    }

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

        Intent intent = new Intent(this, serviceClass);

        try {
            // startForegroundService was introduced in Android Oreo (API 26).
            // Use reflection to maintain compatibility with API < 14.
            Method method = Context.class.getMethod("startForegroundService", Intent.class);
            method.invoke(this, intent);

        } catch (Throwable x) {
            // fallback to start #startService on Android API < 26
            startService(intent);
        }

        if (nativeView != null)
            nativeView.onResume();
        else
            initSDL();
        getHapticFeedbackSettings();
    }

    @Override
    protected void onDestroy() {
        Log.d(TAG, "in onDestroy()");

        if (batteryReceiver != null) {
            unregisterReceiver(batteryReceiver);
            batteryReceiver = null;
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD)
            DownloadUtil.Deinitialise(getApplicationContext());

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
            UsbSerialHelper.Deinitialise(this);
        }

        SoundUtil.Deinitialise();

        if (nativeView != null) {
            nativeView.exitApp();
            nativeView = null;
        }

        // Release the WakeLock instance to re-enable screen timeouts
        if (wakeLock != null) {
            wakeLock.release();
            wakeLock = null;
        }

        IOIOHelper.onDestroyContext();

        deinitialiseNative();

        super.onDestroy();
        Log.d(TAG, "System.exit()");
        System.exit(0);
    }

    @Override
    public boolean onKeyDown(int keyCode, final KeyEvent event) {
        // Overrides Back key to use in our app
        if (nativeView != null) {
            nativeView.onKeyDown(keyCode, event);
            return true;
        } else
            return super.onKeyDown(keyCode, event);
    }

    @Override
    public boolean onKeyUp(int keyCode, final KeyEvent event) {
        if (nativeView != null) {
            nativeView.onKeyUp(keyCode, event);
            return true;
        } else
            return super.onKeyUp(keyCode, event);
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        enableImmersiveModeIfSupported();
        super.onWindowFocusChanged(hasFocus);
    }

    @Override
    public boolean dispatchTouchEvent(final MotionEvent ev) {
        if (nativeView != null) {
            nativeView.onTouchEvent(ev);
            return true;
        } else
            return super.dispatchTouchEvent(ev);
    }

    /**
     * permissions request code
     */
    private final static int REQUEST_CODE_ASK_PERMISSIONS = 1;
    /**
     * Permissions that need to be explicitly requested from end user.
     */
    private static final String[] REQUIRED_SDK_PERMISSIONS = new String[] { Manifest.permission.BLUETOOTH,
            Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WAKE_LOCK, Manifest.permission.INTERNET,
            Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.VIBRATE };

    /**
     * Checks the dynamically-controlled permissions and requests missing permissions from end user.
     */
    protected void checkPermissions() {
        final List<String> missingPermissions = new ArrayList<String>();
        // check all required dynamic permissions
        for (final String permission : REQUIRED_SDK_PERMISSIONS) {
            final int result = ContextCompat.checkSelfPermission(this, permission);
            if (result != PackageManager.PERMISSION_GRANTED) {
                missingPermissions.add(permission);
            }
        }
        if (!missingPermissions.isEmpty()) {
            // request all missing permissions
            final String[] permissions = missingPermissions.toArray(new String[missingPermissions.size()]);
            ActivityCompat.requestPermissions(this, permissions, REQUEST_CODE_ASK_PERMISSIONS);
        } else {
            final int[] grantResults = new int[REQUIRED_SDK_PERMISSIONS.length];
            Arrays.fill(grantResults, PackageManager.PERMISSION_GRANTED);
            onRequestPermissionsResult(REQUEST_CODE_ASK_PERMISSIONS, REQUIRED_SDK_PERMISSIONS, grantResults);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
            @NonNull int[] grantResults) {
        switch (requestCode) {
        case REQUEST_CODE_ASK_PERMISSIONS:
            for (int index = permissions.length - 1; index >= 0; --index) {
                if (grantResults[index] != PackageManager.PERMISSION_GRANTED) {
                    // exit the app if one permission is not granted
                    onRuntimePermissionDenied();
                    return;
                }
            }
            // all permissions are granted
            onRuntimePermissionGranted();
            break;
        }
    }

    private void onRuntimePermissionGranted() {
        LKDistribution.copyLKDistribution(this.getApplication(), false);

        onRuntimePermissionGrantedNative();
    }

    private native void onRuntimePermissionDenied();

    private native void onRuntimePermissionGrantedNative();

    private native void initialiseNative();

    private native void deinitialiseNative();

}