de.localtoast.launchit.BackgroundService.java Source code

Java tutorial

Introduction

Here is the source code for de.localtoast.launchit.BackgroundService.java

Source

/*
 * This file is part of Launch It!.
 * Copyright (c) 2014.
 *
 * Launch It! 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.
 *
 * Launch It! 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 Launch It!.  If not, see <http://www.gnu.org/licenses/>.
 */

package de.localtoast.launchit;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.support.v4.app.NotificationCompat;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Toast;

import net.danlew.android.joda.ResourceZoneInfoProvider;

import java.util.Timer;
import java.util.TimerTask;

import de.localtoast.launchit.applistview.AppListView;
import de.localtoast.launchit.db.SQLiteHelper;
import de.localtoast.launchit.preferences.Settings;
import de.localtoast.launchit.preferences.SettingsActivity;

/**
 * Created by Arne Augenstein on 2/15/14.
 */
public class BackgroundService extends Service {

    private static final int FADING_DURATION_MS = 280;

    private Timer timer = new Timer();
    private AppListUpdater appListUpdater;

    private LinearLayout touchArea;
    private FrameLayout sidebar;

    boolean sidebarVisible = false;

    int touchAreaColor = 0x00000000;
    int receiveTouchEvents = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;

    private AppListView appListView;

    private final BackgroundServiceInterface.Stub binder = new BackgroundServiceInterface.Stub() {
        // TODO make normal class out of this inner class

        @Override
        public void makeTouchAreaInvisible() throws RemoteException {
            touchAreaColor = 0x00000000;
            receiveTouchEvents = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
            refreshTouchArea();
        }

        @Override
        public void makeTouchAreaVisible() throws RemoteException {
            touchAreaColor = 0x992DE397;
            receiveTouchEvents = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
            refreshTouchArea();
        }

        @Override
        public void resizeTouchArea() throws RemoteException {
            refreshTouchArea();
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        // initialize joda time library
        ResourceZoneInfoProvider.init(this);

        appListUpdater = new AppListUpdater();
        timer.scheduleAtFixedRate(appListUpdater, 0, 60000);

        initSidebar();
        initTouchArea();
        WindowManager.LayoutParams params = getTouchAreaLayoutParams();
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.addView(touchArea, params);

        addNotificationIcon();
    }

    private void addNotificationIcon() {
        Context context = getBaseContext();
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
                .setSmallIcon(R.drawable.abc_ab_bottom_solid_dark_holo).setContentTitle("Launch it!")
                .setContentText("Touch for preferences").setOngoing(true);

        Intent resultIntent = new Intent(context, SettingsActivity.class);

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
        // Adds the back stack for the Intent (but not the Intent itself)
        stackBuilder.addParentStack(SettingsActivity.class);
        // Adds the Intent that starts the Activity to the top of the stack
        stackBuilder.addNextIntent(resultIntent);
        PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
        mBuilder.setContentIntent(resultPendingIntent);
        NotificationManager mNotificationManager = (NotificationManager) getSystemService(
                Context.NOTIFICATION_SERVICE);

        mNotificationManager.notify(1, mBuilder.build());
    }

    public void switchToTouchArea() {
        /*
         * Only enter on first run (touchArea == null) or when the sidebar is visible.
         */
        if (touchArea == null || sidebarVisible) {
            sidebarVisible = false;
            if (appListView != null) {
                Animation animation = AnimationUtils.loadAnimation(getBaseContext(), android.R.anim.fade_out);
                animation.setDuration(FADING_DURATION_MS);
                animation.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {
                        // do nothing
                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {
                        switchToTouchAreaPostAnimation();
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {
                        // do nothing
                    }
                });
                appListView.startAnimation(animation);
                appListView.setVisibility(ListView.GONE);
            } else {
                switchToTouchAreaPostAnimation();
            }
        }
    }

    private void switchToTouchAreaPostAnimation() {
        WindowManager.LayoutParams params = getTouchAreaLayoutParams();
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        touchArea.setBackgroundColor(touchAreaColor);
        removeView();
        wm.addView(touchArea, params);
    }

    private void removeView() {
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        try {
            wm.removeView(sidebar);
        } catch (IllegalArgumentException e1) {
            try {
                wm.removeView(touchArea);
            } catch (IllegalArgumentException e2) {
                // if now view was attached, we just do nothing
            }
        }
    }

    private void refreshTouchArea() {
        WindowManager.LayoutParams params = getTouchAreaLayoutParams();
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        touchArea.setBackgroundColor(touchAreaColor);
        removeView();
        wm.addView(touchArea, params);
    }

    private WindowManager.LayoutParams getTouchAreaLayoutParams() {
        Settings settings = new Settings(getBaseContext());
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(settings.getTouchAreaWidth(),
                settings.getTouchAreaHeight(), WindowManager.LayoutParams.TYPE_PHONE,
                receiveTouchEvents | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);

        int horizontalPos = Gravity.RIGHT;
        if (settings.isTouchAreaPositionLeftEdge()) {
            horizontalPos = Gravity.LEFT;
        }
        params.gravity = Gravity.TOP | horizontalPos;
        params.y = settings.getTouchAreaHorizontalPosition();
        return params;
    }

    private void initTouchArea() {
        if (touchArea == null) {

            touchArea = new LinearLayout(this);
            touchArea.setBackgroundColor(touchAreaColor);
            touchArea.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switchToSidebar();
                    return true;
                }
            });
        }
    }

    private void switchToSidebar() {
        if (!sidebarVisible) {
            sidebarVisible = true;

            Context context = getBaseContext();

            WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            WindowManager.LayoutParams params = new WindowManager.LayoutParams(225,
                    WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_PHONE,
                    WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
                    PixelFormat.TRANSLUCENT);
            params.gravity = Gravity.TOP | Gravity.RIGHT;

            removeView();
            wm.addView(sidebar, params);
            // TODO move this animation stuff in some sort of gui class or directly to the view
            Animation animation = AnimationUtils.loadAnimation(context, R.anim.slide_in_right);
            animation.setDuration(FADING_DURATION_MS);
            appListView.startAnimation(animation);
            appListView.setVisibility(View.VISIBLE);
        }
    }

    private void initSidebar() {
        if (sidebar == null) {
            Context context = getBaseContext();
            sidebar = new FrameLayout(context);
            appListView = new AppListView(this);
            sidebar.addView(appListView);
            sidebar.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    /*
                     * Close the app list, when element outside of list is touched.
                     */
                    if (sidebarVisible) {
                        switchToTouchArea();
                    }
                    return false;
                }
            });
        }
    }

    public void startApp(String packageName) {
        Intent intent = getPackageManager().getLaunchIntentForPackage(packageName);

        if (intent == null) {
            Toast toast = Toast.makeText(getBaseContext(),
                    "Launch it! does not have the permission to launch this app", Toast.LENGTH_SHORT);
            toast.show();
        } else {
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
            new SQLiteHelper(this).incrementPriorityCounter(packageName);
            appListUpdater.addNewRunningApp(packageName);
            appListView.update();
            switchToTouchArea();
        }
    }

    @Override
    public void onDestroy() {
        removeView();
        super.onDestroy();
    }

    private class AppListUpdater extends TimerTask {
        private AppListHelper appListHelper;

        public AppListUpdater() {
            appListHelper = new AppListHelper(BackgroundService.this);
        }

        @Override
        public void run() {
            appListHelper.updateRunningTasks();
            if (appListView != null) {
                // The following action has to be run from the GUI thread
                Handler handler = new Handler(Looper.getMainLooper());
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        appListView.update();
                    }
                });
            }
        }

        public void addNewRunningApp(String packageName) {
            appListHelper.addNewRunningApp(packageName);
        }
    }

}