com.mumu.joshautomation.HeadService.java Source code

Java tutorial

Introduction

Here is the source code for com.mumu.joshautomation.HeadService.java

Source

/*
 * Copyright (C) 2017 The Josh Tool Project
 *
 * 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.mumu.joshautomation;

import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Point;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.support.v7.app.AlertDialog;
import android.support.v4.app.NotificationCompat;
import android.support.v7.view.ContextThemeWrapper;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;

import com.mumu.joshautomation.caocao.FlushJob;
import com.mumu.joshautomation.caocao.FlushMoneyJob;
import com.mumu.joshautomation.fgo.AutoBattleJob;
import com.mumu.joshautomation.fgo.LoopBattleJob;
import com.mumu.joshautomation.fgo.NewFlushJob;
import com.mumu.joshautomation.fgo.PureBattleJob;
import com.mumu.joshautomation.fgo.TWAutoLoginJob;
import com.mumu.joshautomation.ro.ROAutoDrinkJob;
import com.mumu.joshautomation.fgo.AutoBoxJob;
import com.mumu.joshautomation.screencapture.PointSelectionActivity;
import com.mumu.joshautomation.script.AutoJobEventListener;
import com.mumu.joshautomation.script.AutoJobHandler;
import com.mumu.joshautomation.script.DefinitionLoader;
import com.mumu.joshautomation.shinobi.ShinobiLoopBattleJob;
import com.mumu.libjoshgame.JoshGameLibrary;
import com.mumu.libjoshgame.Log;
import com.mumu.libjoshgame.ScreenPoint;

import java.util.ArrayList;

public class HeadService extends Service implements AutoJobEventListener {
    private static final String TAG = "HeadService";
    private final Handler mHandler = new Handler();
    private final String mPngFilePath = Environment.getExternalStorageDirectory().toString() + "/select.png";
    private final String mDumpFilePath = Environment.getExternalStorageDirectory().toString() + "/select.dump";
    private static final int mUpdateUIInterval = 100;
    private static final int mMessageLastTime = 20; //20 seconds
    private Context mContext;

    // View objects
    private WindowManager mWindowManager;
    private ArrayList<HeadIconView> mHeadIconList;
    private static final int IDX_HEAD_ICON = 0;
    private static final int IDX_MSG_TEXT = 1;
    private static final int IDX_CAPTURE_ICON = 2;
    private static final int IDX_SETTING_ICON = 3;
    private static final int IDX_PLAY_ICON = 4;

    private int mTouchHeadIconCount = 0;
    private int mSameMsgCount = 0;
    private String mMessageText = "";
    private String mLastMessage = "";
    private boolean mScriptRunning = false;
    private boolean mMessageThreadRunning = false;
    private static int mDumpCount = 0;

    private JoshGameLibrary mGL;
    private AppPreferenceValue mAPV;
    private AutoJobHandler mAutoJobHandler;
    private static boolean mAutoJobAdded = false;

    /* ==========================
     * Update UI Thread
     * ==========================
     */
    private final Runnable updateRunnable = new Runnable() {
        public void run() {
            updateUI();
        }
    };

    private void updateUI() {
        if (mLastMessage.equals(mMessageText)) {
            mSameMsgCount++;
            if (mSameMsgCount > mMessageLastTime * 10) { //a same message will last for mMessageLastTime second on screen
                ((TextView) mHeadIconList.get(IDX_MSG_TEXT).getView()).setText("");
            }
        } else {
            mLastMessage = mMessageText;
            mSameMsgCount = 0;
            ((TextView) mHeadIconList.get(IDX_MSG_TEXT).getView()).setText(mMessageText);
        }

        if (!mScriptRunning) {
            mHeadIconList.get(IDX_PLAY_ICON).getImageView().setImageResource(R.drawable.ic_play);
        }
    }

    private final Runnable mDumpScreenRunnable = new Runnable() {
        @Override
        public void run() {
            /* Call our library to dump screen, this might take a while */
            try {
                mGL.getCaptureService().dumpScreenPNG(mPngFilePath);
                mGL.getCaptureService().dumpScreen(mDumpFilePath);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            /* show icon view back */
            configAllIconShowing(HeadIconView.VISIBLE);

            /* show result screen */
            Intent intent = new Intent();
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setClass(HeadService.this, PointSelectionActivity.class);
            startActivity(intent);
        }
    };

    /* ==========================
     * Service Basic
     * ==========================
     */
    @Override
    public IBinder onBind(Intent intent) {
        // Not used
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        mContext = this;

        mAPV = AppPreferenceValue.getInstance();
        mAPV.init(mContext);

        // initial game panel view
        initGamePanelViews();

        // initial game library, this should never fail and follow up initGamePanelViews
        initGameLibrary();

        // initial a notification
        initNotification();

        mMessageThreadRunning = true;
        new GetMessageThread().start();
    }

    // provide our service not be able to kill
    private void initNotification() {
        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0);

        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_bookmarked).setContentTitle("?")
                .setContentText("?").setContentIntent(contentIntent); //Required on Gingerbread and below

        startForeground(1235, mBuilder.build());
    }

    private void initGamePanelViews() {
        mHeadIconList = new ArrayList<>();
        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

        // Head Icon
        HeadIconView headIcon = new HeadIconView(new ImageView(this), mWindowManager, 0, 0);
        headIcon.getImageView().setImageResource(R.mipmap.ic_launcher);
        headIcon.setOnTapListener(new HeadIconView.OnTapListener() {
            @Override
            public void onTap(View view) {
                configHeadIconShowing(
                        (getCurrentHeadIconVisibility() == HeadIconView.VISIBLE ? HeadIconView.INVISIBLE
                                : HeadIconView.VISIBLE));
            }

            @Override
            public void onLongPress(View view) {
                showExitConfirmDialog();
            }
        });
        mHeadIconList.add(headIcon);

        // Message Text Icon
        HeadIconView msgText = new HeadIconView(new TextView(this), mWindowManager, 140, 45);
        msgText.getTextView().setTextColor(Color.BLACK);
        msgText.getView().setBackgroundColor(Color.WHITE);
        mHeadIconList.add(msgText);

        // Capture Icon
        HeadIconView captureIcon = new HeadIconView(new ImageView(this), mWindowManager, 0, 120);
        captureIcon.getImageView().setImageResource(R.drawable.ic_menu_camera);
        captureIcon.setOnTapListener(new HeadIconView.OnTapListener() {
            @Override
            public void onTap(View view) {
                configCapture();
            }

            @Override
            public void onLongPress(View view) {

            }
        });
        mHeadIconList.add(captureIcon);

        // Setting Icon
        HeadIconView settingIcon = new HeadIconView(new ImageView(this), mWindowManager, 120, 120);
        settingIcon.getImageView().setImageResource(R.drawable.ic_menu_settings);
        settingIcon.setOnTapListener(new HeadIconView.OnTapListener() {
            @Override
            public void onTap(View view) {
                configSettings(false);
            }

            @Override
            public void onLongPress(View view) {
                Log.d(TAG, "config setting icon");
                configSettings(true);
            }
        });
        mHeadIconList.add(settingIcon);

        // Start and Stop control Icon
        HeadIconView startIcon = new HeadIconView(new ImageView(this), mWindowManager, 240, 120);
        startIcon.getImageView().setImageResource(R.drawable.ic_play);
        startIcon.setOnTapListener(new HeadIconView.OnTapListener() {
            @Override
            public void onTap(View view) {
                configScriptStatus();
            }

            @Override
            public void onLongPress(View view) {

            }
        });
        mHeadIconList.add(startIcon);

        // Share the same on move listener for moving at the same time
        HeadIconView.OnMoveListener moveListener = new HeadIconView.OnMoveListener() {
            @Override
            public void onMove(HeadIconView view, int initialX, int initialY, float initialTouchX,
                    float initialTouchY, MotionEvent event) {
                // we limit the initiator of moving to only head icon
                if (view == mHeadIconList.get(IDX_HEAD_ICON)) {
                    for (HeadIconView icon : mHeadIconList) {
                        icon.moveIconDefault(initialX, initialY, initialTouchX, initialTouchY, event);
                    }
                }
            }
        };

        // Set all to add
        for (HeadIconView icon : mHeadIconList) {
            icon.addView();
            icon.setOnMoveListener(moveListener);
        }

        // Set default visibility
        configHeadIconShowing(HeadIconView.VISIBLE);
    }

    private void initGameLibrary() {
        int w, h;
        int userWidth, userHeight, userAmbValue, userTouchShift;
        int userScreenXOffset, userScreenYOffset, userWaitTransactTime;

        // try to get user's setting
        try {
            userWidth = Integer.parseInt(mAPV.getPrefs().getString("userSetWidth", "0"));
            userHeight = Integer.parseInt(mAPV.getPrefs().getString("userSetHeight", "0"));
            userAmbValue = Integer.parseInt(mAPV.getPrefs().getString("userAmbValue", "0"));
            userTouchShift = Integer.parseInt(mAPV.getPrefs().getString("userSetTouchShift", "0"));
            userScreenXOffset = Integer.parseInt(mAPV.getPrefs().getString("userSetScreenXOffset", "0"));
            userScreenYOffset = Integer.parseInt(mAPV.getPrefs().getString("userSetScreenYOffset", "0"));
            userWaitTransactTime = Integer
                    .parseInt(mAPV.getPrefs().getString("userSetWaitTransactionDoneTime", "0"));
        } catch (NumberFormatException e) {
            Log.e(TAG, "Setting value format error: " + e.getMessage());
            userWidth = 0;
            userHeight = 0;
            userAmbValue = 0;
            userTouchShift = 0;
            userScreenXOffset = 0;
            userScreenYOffset = 0;
            userWaitTransactTime = 0;
        }

        // Initial DefinitionLoader
        DefinitionLoader.getInstance().setResources(mContext.getResources());

        Display display = mWindowManager.getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);

        // we always treat the short edge as width
        // TODO: we need to find a new way to get actual panel width and height
        if (size.x > size.y) {
            w = size.y;
            if (size.x > 2000)
                h = 2160;
            else
                h = size.x;
        } else {
            w = size.x;
            if (size.y > 2000)
                h = 2160;
            else
                h = size.y;
        }

        mGL = JoshGameLibrary.getInstance();
        mGL.setContext(mContext);

        // Check if user override settings
        if (userWidth != 0 && userHeight != 0)
            mGL.setScreenDimension(userWidth, userHeight);
        else
            mGL.setScreenDimension(w, h);

        mGL.getCaptureService().setChatty(mAPV.getPrefs().getBoolean("captureServiceChatty", false));

        if (userAmbValue != 0)
            mGL.setAmbiguousRange(new int[] { userAmbValue, userAmbValue, userAmbValue });
        else
            mGL.setAmbiguousRange(new int[] { JoshGameLibrary.DEFAULT_AMBIGUOUS_VALUE,
                    JoshGameLibrary.DEFAULT_AMBIGUOUS_VALUE, JoshGameLibrary.DEFAULT_AMBIGUOUS_VALUE });

        if (userScreenXOffset != 0 || userScreenYOffset != 0)
            mGL.setScreenOffset(userScreenXOffset, userScreenYOffset, ScreenPoint.SO_Portrait);

        if (userTouchShift != 0)
            mGL.setTouchShift(userTouchShift);
        else
            mGL.setTouchShift(JoshGameLibrary.DEFAULT_TOUCH_SHIFT);

        if (userWaitTransactTime != 0)
            mGL.setWaitTransactionTime(userWaitTransactTime);
        else
            mGL.setWaitTransactionTime(JoshGameLibrary.DEFAULT_WAIT_TRANSACT_TIME);

        if (mAPV.getPrefs().getBoolean("ssEnabled", false)) {
            String pn = mAPV.getPrefs().getString("ssPackageName", "");
            String sn = mAPV.getPrefs().getString("ssServiceName", "");
            String in = mAPV.getPrefs().getString("ssInterfaceName", "");
            int code = Integer.parseInt(mAPV.getPrefs().getString("ssTransactCode", "0"));
            mGL.setHackParams(pn, sn, in, code);
            mGL.setHackSS(true);
        } else {
            mGL.setHackSS(false);
        }

        mGL.getCaptureService().setChatty(mAPV.getPrefs().getBoolean("captureServiceChatty", false));

        mAutoJobHandler = AutoJobHandler.getHandler();

        if (!mAutoJobAdded) {
            mAutoJobHandler.addJob(new LoopBattleJob());
            mAutoJobHandler.addJob(new AutoBattleJob());
            mAutoJobHandler.addJob(new PureBattleJob());
            mAutoJobHandler.addJob(new NewFlushJob());
            mAutoJobHandler.addJob(new TWAutoLoginJob());
            mAutoJobHandler.addJob(new ShinobiLoopBattleJob());
            mAutoJobHandler.addJob(new FlushJob());
            mAutoJobHandler.addJob(new FlushMoneyJob());
            mAutoJobHandler.addJob(new ROAutoDrinkJob());
            mAutoJobHandler.addJob(new AutoBoxJob());

            mAutoJobHandler.setJobEventListener(LoopBattleJob.jobName, this);
            mAutoJobHandler.setJobEventListener(PureBattleJob.jobName, this);
            mAutoJobHandler.setJobEventListener(AutoBattleJob.jobName, this);
            mAutoJobHandler.setJobEventListener(NewFlushJob.jobName, this);
            mAutoJobHandler.setJobEventListener(TWAutoLoginJob.jobName, this);
            mAutoJobHandler.setJobEventListener(ShinobiLoopBattleJob.jobName, this);
            mAutoJobHandler.setJobEventListener(FlushJob.jobName, this);
            mAutoJobHandler.setJobEventListener(FlushMoneyJob.jobName, this);
            mAutoJobHandler.setJobEventListener(AutoBoxJob.jobName, this);

            //add service itself to job
            mAutoJobHandler.setExtra(LoopBattleJob.jobName, this);
            mAutoJobHandler.setExtra(ShinobiLoopBattleJob.jobName, this);
            mAutoJobHandler.setExtra(FlushJob.jobName, this);
            mAutoJobHandler.setExtra(FlushMoneyJob.jobName, this);
            mAutoJobAdded = true;
        }
    }

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

        // Game tool
        for (HeadIconView icon : mHeadIconList) {
            icon.removeView();
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        if (intent != null) {
            final String action = intent.getAction();
            if (action != null) {
                configHeadIconShowing(HeadIconView.VISIBLE);
            }
        }
        return START_STICKY;
    }

    /* ==========================
     * Icon visibility
     * ==========================
     */
    public int getCurrentHeadIconVisibility() {
        if (mTouchHeadIconCount % 2 == 0)
            return HeadIconView.INVISIBLE;
        else
            return HeadIconView.VISIBLE;
    }

    private void configHeadIconShowing(int visible) {
        // If current status is what we want, return here
        if (getCurrentHeadIconVisibility() == visible)
            return;

        // Increase icon touch count
        mTouchHeadIconCount++;

        for (HeadIconView view : mHeadIconList) {
            if (view == mHeadIconList.get(IDX_HEAD_ICON) || view == mHeadIconList.get(IDX_MSG_TEXT))
                continue;
            view.setVisibility(visible);
        }
    }

    private void configAllIconShowing(int visible) {
        for (HeadIconView view : mHeadIconList) {
            view.setVisibility(visible);
        }
    }

    private void showExitConfirmDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(
                new ContextThemeWrapper(mContext, R.style.MyDialogStyle))
                        .setTitle(getString(R.string.headservice_stop_title))
                        .setMessage(getString(R.string.headservice_stop_info)).setPositiveButton(
                                getString(R.string.headservice_stop_button), new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        // Let's do some background stuff
                                        stopSelf();
                                    }
                                })
                        .setNegativeButton(getString(R.string.startup_cancel),
                                new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                    }
                                });
        AlertDialog alert = builder.create();
        Window win = alert.getWindow();
        if (win != null)
            win.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
        alert.show();
    }

    /* ==========================
     * Tap behavior of icons
     * ==========================
     */
    private void configCapture() {
        // head service is responsible for setting orientation
        int orientation = getResources().getConfiguration().orientation;
        if (orientation == 1)
            mGL.setGameOrientation(ScreenPoint.SO_Portrait);
        else
            mGL.setGameOrientation(ScreenPoint.SO_Landscape);

        configAllIconShowing(HeadIconView.INVISIBLE);
        mHandler.postDelayed(mDumpScreenRunnable, 100);
    }

    private void configSettings(boolean isLongPress) {
        if (isLongPress) {
            String filename = mDumpFilePath + mDumpCount;
            try {
                mGL.getCaptureService().dumpScreen(filename);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            mMessageText = "Dump count = " + mDumpCount;
            mDumpCount++;
        } else {
            mMessageText = "";
            Intent intent = new Intent();
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setClass(HeadService.this, AppPreferenceActivity.class);
            startActivity(intent);
        }
    }

    private void configScriptStatus() {
        String currentSelectIndexPref = mAPV.getPrefs().getString("scriptSelectPref", "0");
        int currentSelectIndex = Integer.parseInt(currentSelectIndexPref);
        Log.d(TAG, "select " + currentSelectIndex);

        if (!mScriptRunning) {
            mAutoJobHandler.startJob(currentSelectIndex);
            mHeadIconList.get(IDX_PLAY_ICON).getImageView().setImageResource(R.drawable.ic_pause);
        } else {
            mAutoJobHandler.stopJob(currentSelectIndex);
            mHeadIconList.get(IDX_PLAY_ICON).getImageView().setImageResource(R.drawable.ic_play);
        }

        mScriptRunning = !mScriptRunning;
    }

    /* ==========================
     * Message handler
     * ==========================
     */
    @Override
    public void onEventReceived(String msg, Object extra) {
        mMessageText = msg;
    }

    @Override
    public void onJobDone(String job) {
        Log.d(TAG, "Job " + job + " has done");

        if (job.equals(PureBattleJob.jobName)) {
            mMessageText = "?";
        } else if (job.equals(AutoBattleJob.jobName)) {
            mScriptRunning = false;
            mMessageText = "??";
        }
    }

    private class GetMessageThread extends Thread {
        public void run() {
            while (mMessageThreadRunning) {
                mHandler.post(updateRunnable);
                try {
                    Thread.sleep(mUpdateUIInterval);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}