diff options
| author | Charles Lombardo <clombardo169@gmail.com> | 2023-03-07 13:19:05 -0500 | 
|---|---|---|
| committer | bunnei <bunneidev@gmail.com> | 2023-06-03 00:05:35 -0700 | 
| commit | 39a65f8446d9301e48b40079707e075495336356 (patch) | |
| tree | 4e0646ddb39fb86e52b322ac19f0ac2a083d7fd2 /src/android | |
| parent | 7cd72a7c6df242f4e47099647a095f76698bb400 (diff) | |
android: Convert EmulationActivity to Kotlin
Diffstat (limited to 'src/android')
| -rw-r--r-- | src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.java | 347 | ||||
| -rw-r--r-- | src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt | 286 | 
2 files changed, 286 insertions, 347 deletions
| diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.java deleted file mode 100644 index 343bc032b..000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.java +++ /dev/null @@ -1,347 +0,0 @@ -package org.yuzu.yuzu_emu.activities; - -import android.app.Activity; -import android.content.Intent; -import android.content.SharedPreferences; -import android.graphics.Rect; -import android.os.Bundle; -import android.os.Handler; -import android.preference.PreferenceManager; -import android.view.InputDevice; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.WindowManager; -import android.widget.SeekBar; -import android.widget.TextView; - -import androidx.annotation.IntDef; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatActivity; -import androidx.core.app.NotificationManagerCompat; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; -import androidx.fragment.app.FragmentManager; - -import org.yuzu.yuzu_emu.NativeLibrary; -import org.yuzu.yuzu_emu.R; -import org.yuzu.yuzu_emu.fragments.EmulationFragment; -import org.yuzu.yuzu_emu.fragments.MenuFragment; -import org.yuzu.yuzu_emu.utils.ControllerMappingHelper; -import org.yuzu.yuzu_emu.utils.ForegroundService; - -import java.lang.annotation.Retention; - -import static java.lang.annotation.RetentionPolicy.SOURCE; - -public final class EmulationActivity extends AppCompatActivity { -    private static final String BACKSTACK_NAME_MENU = "menu"; - -    private static final String BACKSTACK_NAME_SUBMENU = "submenu"; - -    public static final String EXTRA_SELECTED_GAME = "SelectedGame"; -    public static final String EXTRA_SELECTED_TITLE = "SelectedTitle"; -    public static final int MENU_ACTION_EDIT_CONTROLS_PLACEMENT = 0; -    public static final int MENU_ACTION_TOGGLE_CONTROLS = 1; -    public static final int MENU_ACTION_ADJUST_SCALE = 2; -    public static final int MENU_ACTION_EXIT = 3; -    public static final int MENU_ACTION_SHOW_FPS = 4; -    public static final int MENU_ACTION_RESET_OVERLAY = 6; -    public static final int MENU_ACTION_SHOW_OVERLAY = 7; -    public static final int MENU_ACTION_OPEN_SETTINGS = 8; -    private static final int EMULATION_RUNNING_NOTIFICATION = 0x1000; -    private View mDecorView; -    private EmulationFragment mEmulationFragment; -    private SharedPreferences mPreferences; -    private ControllerMappingHelper mControllerMappingHelper; -    // TODO(bunnei): Disable notifications until we support app suspension. -//    private Intent foregroundService; -    private boolean activityRecreated; -    private String mSelectedTitle; -    private String mPath; - -    private boolean mMenuVisible; - -    public static void launch(FragmentActivity activity, String path, String title) { -        Intent launcher = new Intent(activity, EmulationActivity.class); - -        launcher.putExtra(EXTRA_SELECTED_GAME, path); -        launcher.putExtra(EXTRA_SELECTED_TITLE, title); -        activity.startActivity(launcher); -    } - -    public static void tryDismissRunningNotification(Activity activity) { -        // TODO(bunnei): Disable notifications until we support app suspension. -//        NotificationManagerCompat.from(activity).cancel(EMULATION_RUNNING_NOTIFICATION); -    } - -    @Override -    protected void onDestroy() { -        // TODO(bunnei): Disable notifications until we support app suspension. -//        stopService(foregroundService); -        super.onDestroy(); -    } - -    @Override -    protected void onCreate(Bundle savedInstanceState) { -        super.onCreate(savedInstanceState); - -        if (savedInstanceState == null) { -            // Get params we were passed -            Intent gameToEmulate = getIntent(); -            mPath = gameToEmulate.getStringExtra(EXTRA_SELECTED_GAME); -            mSelectedTitle = gameToEmulate.getStringExtra(EXTRA_SELECTED_TITLE); -            activityRecreated = false; -        } else { -            activityRecreated = true; -            restoreState(savedInstanceState); -        } - -        mControllerMappingHelper = new ControllerMappingHelper(); - -        // Get a handle to the Window containing the UI. -        mDecorView = getWindow().getDecorView(); -        mDecorView.setOnSystemUiVisibilityChangeListener(visibility -> -        { -            if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { -                // Go back to immersive fullscreen mode in 3s -                Handler handler = new Handler(getMainLooper()); -                handler.postDelayed(this::enableFullscreenImmersive, 3000 /* 3s */); -            } -        }); -        // Set these options now so that the SurfaceView the game renders into is the right size. -        enableFullscreenImmersive(); - -        setTheme(R.style.YuzuEmulationBase); - -        setContentView(R.layout.activity_emulation); - -        // Find or create the EmulationFragment -        mEmulationFragment = (EmulationFragment) getSupportFragmentManager() -                .findFragmentById(R.id.frame_emulation_fragment); -        if (mEmulationFragment == null) { -            mEmulationFragment = EmulationFragment.newInstance(mPath); -            getSupportFragmentManager().beginTransaction() -                    .add(R.id.frame_emulation_fragment, mEmulationFragment) -                    .commit(); -        } - -        setTitle(mSelectedTitle); - -        mPreferences = PreferenceManager.getDefaultSharedPreferences(this); - -        // Start a foreground service to prevent the app from getting killed in the background -        // TODO(bunnei): Disable notifications until we support app suspension. -//        foregroundService = new Intent(EmulationActivity.this, ForegroundService.class); -//        startForegroundService(foregroundService); -    } - -    @Override -    protected void onSaveInstanceState(@NonNull Bundle outState) { -        outState.putString(EXTRA_SELECTED_GAME, mPath); -        outState.putString(EXTRA_SELECTED_TITLE, mSelectedTitle); -        super.onSaveInstanceState(outState); -    } - -    protected void restoreState(Bundle savedInstanceState) { -        mPath = savedInstanceState.getString(EXTRA_SELECTED_GAME); -        mSelectedTitle = savedInstanceState.getString(EXTRA_SELECTED_TITLE); - -        // If an alert prompt was in progress when state was restored, retry displaying it -        NativeLibrary.retryDisplayAlertPrompt(); -    } - -    @Override -    public void onRestart() { -        super.onRestart(); -    } - -    @Override -    public void onBackPressed() { -        toggleMenu(); -    } - -    private void enableFullscreenImmersive() { -        getWindow().getAttributes().layoutInDisplayCutoutMode= -                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; - -        // It would be nice to use IMMERSIVE_STICKY, but that doesn't show the toolbar. -        mDecorView.setSystemUiVisibility( -                View.SYSTEM_UI_FLAG_LAYOUT_STABLE | -                        View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | -                        View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | -                        View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | -                        View.SYSTEM_UI_FLAG_FULLSCREEN | -                        View.SYSTEM_UI_FLAG_IMMERSIVE); -    } - -    public void handleMenuAction(int action) { -        switch (action) { -            case MENU_ACTION_EXIT: -                mEmulationFragment.stopEmulation(); -                finish(); -                break; -        } -    } - -    private void editControlsPlacement() { -        if (mEmulationFragment.isConfiguringControls()) { -            mEmulationFragment.stopConfiguringControls(); -        } else { -            mEmulationFragment.startConfiguringControls(); -        } -    } - -    private void adjustScale() { -        LayoutInflater inflater = LayoutInflater.from(this); -        View view = inflater.inflate(R.layout.dialog_seekbar, null); - -        final SeekBar seekbar = view.findViewById(R.id.seekbar); -        final TextView value = view.findViewById(R.id.text_value); -        final TextView units = view.findViewById(R.id.text_units); - -        seekbar.setMax(150); -        seekbar.setProgress(mPreferences.getInt("controlScale", 50)); -        seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { -            public void onStartTrackingTouch(SeekBar seekBar) { -            } - -            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { -                value.setText(String.valueOf(progress + 50)); -            } - -            public void onStopTrackingTouch(SeekBar seekBar) { -                setControlScale(seekbar.getProgress()); -            } -        }); - -        value.setText(String.valueOf(seekbar.getProgress() + 50)); -        units.setText("%"); - -        AlertDialog.Builder builder = new AlertDialog.Builder(this); -        builder.setTitle(R.string.emulation_control_scale); -        builder.setView(view); -        final int previousProgress = seekbar.getProgress(); -        builder.setNegativeButton(android.R.string.cancel, (dialogInterface, i) -> { -            setControlScale(previousProgress); -        }); -        builder.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> -        { -            setControlScale(seekbar.getProgress()); -        }); -        builder.setNeutralButton(R.string.slider_default, (dialogInterface, i) -> { -            setControlScale(50); -        }); - -        AlertDialog alertDialog = builder.create(); -        alertDialog.show(); -    } - -    private void setControlScale(int scale) { -        SharedPreferences.Editor editor = mPreferences.edit(); -        editor.putInt("controlScale", scale); -        editor.apply(); -        mEmulationFragment.refreshInputOverlay(); -    } - -    private void resetOverlay() { -        new AlertDialog.Builder(this) -                .setTitle(getString(R.string.emulation_touch_overlay_reset)) -                .setPositiveButton(android.R.string.yes, (dialogInterface, i) -> mEmulationFragment.resetInputOverlay()) -                .setNegativeButton(android.R.string.cancel, (dialogInterface, i) -> { -                }) -                .create() -                .show(); -    } - -    private static boolean areCoordinatesOutside(@Nullable View view, float x, float y) -    { -        if (view == null) -        { -            return true; -        } - -        Rect viewBounds = new Rect(); -        view.getGlobalVisibleRect(viewBounds); -        return !viewBounds.contains(Math.round(x), Math.round(y)); -    } - -    @Override -    public boolean dispatchTouchEvent(MotionEvent event) -    { -        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) -        { -            boolean anyMenuClosed = false; - -            Fragment submenu = getSupportFragmentManager().findFragmentById(R.id.frame_submenu); -            if (submenu != null && areCoordinatesOutside(submenu.getView(), event.getX(), event.getY())) -            { -                closeSubmenu(); -                submenu = null; -                anyMenuClosed = true; -            } - -            if (submenu == null) -            { -                Fragment menu = getSupportFragmentManager().findFragmentById(R.id.frame_menu); -                if (menu != null && areCoordinatesOutside(menu.getView(), event.getX(), event.getY())) -                { -                    closeMenu(); -                    anyMenuClosed = true; -                } -            } - -            if (anyMenuClosed) -            { -                return true; -            } -        } - -        return super.dispatchTouchEvent(event); -    } - -    public boolean isActivityRecreated() { -        return activityRecreated; -    } - -    @Retention(SOURCE) -    @IntDef({MENU_ACTION_EDIT_CONTROLS_PLACEMENT, MENU_ACTION_TOGGLE_CONTROLS, MENU_ACTION_ADJUST_SCALE, -            MENU_ACTION_EXIT, MENU_ACTION_SHOW_FPS, MENU_ACTION_RESET_OVERLAY, MENU_ACTION_SHOW_OVERLAY, MENU_ACTION_OPEN_SETTINGS}) -    public @interface MenuAction { -    } - -    private boolean closeSubmenu() -    { -        return getSupportFragmentManager().popBackStackImmediate(BACKSTACK_NAME_SUBMENU, -                FragmentManager.POP_BACK_STACK_INCLUSIVE); -    } - -    private boolean closeMenu() -    { -        mMenuVisible = false; -        return getSupportFragmentManager().popBackStackImmediate(BACKSTACK_NAME_MENU, -                FragmentManager.POP_BACK_STACK_INCLUSIVE); -    } - -    private void toggleMenu() -    { -        if (!closeMenu()) { -            // Removing the menu failed, so that means it wasn't visible. Add it. -            Fragment fragment = MenuFragment.newInstance(); -            getSupportFragmentManager().beginTransaction() -                    .setCustomAnimations( -                            R.animator.menu_slide_in_from_start, -                            R.animator.menu_slide_out_to_start, -                            R.animator.menu_slide_in_from_start, -                            R.animator.menu_slide_out_to_start) -                    .add(R.id.frame_menu, fragment) -                    .addToBackStack(BACKSTACK_NAME_MENU) -                    .commit(); -            mMenuVisible = true; -        } -    } - -} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt new file mode 100644 index 000000000..bd71a3653 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt @@ -0,0 +1,286 @@ +package org.yuzu.yuzu_emu.activities + +import android.app.Activity +import android.content.DialogInterface +import android.content.Intent +import android.graphics.Rect +import android.os.Bundle +import android.view.LayoutInflater +import android.view.MotionEvent +import android.view.View +import android.view.WindowManager +import android.widget.TextView +import androidx.activity.OnBackPressedCallback +import androidx.annotation.IntDef +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import androidx.fragment.app.FragmentManager +import androidx.preference.PreferenceManager +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.slider.Slider +import com.google.android.material.slider.Slider.OnChangeListener +import org.yuzu.yuzu_emu.NativeLibrary +import org.yuzu.yuzu_emu.R +import org.yuzu.yuzu_emu.features.settings.model.Settings +import org.yuzu.yuzu_emu.fragments.EmulationFragment +import org.yuzu.yuzu_emu.fragments.MenuFragment +import org.yuzu.yuzu_emu.utils.ControllerMappingHelper +import kotlin.math.roundToInt + +open class EmulationActivity : AppCompatActivity() { +    private var controllerMappingHelper: ControllerMappingHelper? = null + +    // TODO(bunnei): Disable notifications until we support app suspension. +    //private Intent foregroundService; + +    var isActivityRecreated = false +    private var selectedTitle: String? = null +    private var path: String? = null +    private var menuVisible = false +    private var emulationFragment: EmulationFragment? = null + +    override fun onDestroy() { +        // TODO(bunnei): Disable notifications until we support app suspension. +        //stopService(foregroundService); +        super.onDestroy() +    } + +    override fun onCreate(savedInstanceState: Bundle?) { +        super.onCreate(savedInstanceState) +        if (savedInstanceState == null) { +            // Get params we were passed +            val gameToEmulate = intent +            path = gameToEmulate.getStringExtra(EXTRA_SELECTED_GAME) +            selectedTitle = gameToEmulate.getStringExtra(EXTRA_SELECTED_TITLE) +            isActivityRecreated = false +        } else { +            isActivityRecreated = true +            restoreState(savedInstanceState) +        } +        controllerMappingHelper = ControllerMappingHelper() + +        // Set these options now so that the SurfaceView the game renders into is the right size. +        enableFullscreenImmersive() + +        setContentView(R.layout.activity_emulation) + +        // Find or create the EmulationFragment +        var emulationFragment = +            supportFragmentManager.findFragmentById(R.id.frame_emulation_fragment) as EmulationFragment? +        if (emulationFragment == null) { +            emulationFragment = EmulationFragment.newInstance(path) +            supportFragmentManager.beginTransaction() +                .add(R.id.frame_emulation_fragment, emulationFragment) +                .commit() +        } +        title = selectedTitle + +        // Start a foreground service to prevent the app from getting killed in the background +        // TODO(bunnei): Disable notifications until we support app suspension. +        //foregroundService = new Intent(EmulationActivity.this, ForegroundService.class); +        //startForegroundService(foregroundService); + +        onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { +            override fun handleOnBackPressed() { +                toggleMenu() +            } +        }) +    } + +    override fun onSaveInstanceState(outState: Bundle) { +        outState.putString(EXTRA_SELECTED_GAME, path) +        outState.putString(EXTRA_SELECTED_TITLE, selectedTitle) +        super.onSaveInstanceState(outState) +    } + +    private fun restoreState(savedInstanceState: Bundle) { +        path = savedInstanceState.getString(EXTRA_SELECTED_GAME) +        selectedTitle = savedInstanceState.getString(EXTRA_SELECTED_TITLE) + +        // If an alert prompt was in progress when state was restored, retry displaying it +        NativeLibrary.retryDisplayAlertPrompt() +    } + +    private fun enableFullscreenImmersive() { +        window.attributes.layoutInDisplayCutoutMode = +            WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES + +        // It would be nice to use IMMERSIVE_STICKY, but that doesn't show the toolbar. +        window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or +                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or +                View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or +                View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or +                View.SYSTEM_UI_FLAG_FULLSCREEN or +                View.SYSTEM_UI_FLAG_IMMERSIVE +    } + +    fun handleMenuAction(action: Int) { +        when (action) { +            MENU_ACTION_EXIT -> { +                emulationFragment!!.stopEmulation() +                finish() +            } +        } +    } + +    private fun editControlsPlacement() { +        if (emulationFragment!!.isConfiguringControls) { +            emulationFragment!!.stopConfiguringControls() +        } else { +            emulationFragment!!.startConfiguringControls() +        } +    } + +    private fun adjustScale() { +        val inflater = LayoutInflater.from(this) +        val view = inflater.inflate(R.layout.dialog_slider, null) +        val slider = view.findViewById<Slider>(R.id.slider) +        val textValue = view.findViewById<TextView>(R.id.text_value) +        val units = view.findViewById<TextView>(R.id.text_units) + +        slider.valueTo = 150F +        slider.value = PreferenceManager.getDefaultSharedPreferences(applicationContext) +            .getInt(Settings.PREF_CONTROL_SCALE, 50).toFloat() +        slider.addOnChangeListener(OnChangeListener { _, value, _ -> +            textValue.text = value.toString() +            setControlScale(value.toInt()) +        }) +        textValue.text = slider.value.toString() +        units.text = "%" +        MaterialAlertDialogBuilder(this) +            .setTitle(R.string.emulation_control_scale) +            .setView(view) +            .setNegativeButton(android.R.string.cancel, null) +            .setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> +                setControlScale(slider.value.toInt()) +            } +            .setNeutralButton(R.string.slider_default) { _: DialogInterface?, _: Int -> +                setControlScale(50) +            } +            .show() +    } + +    private fun setControlScale(scale: Int) { +        PreferenceManager.getDefaultSharedPreferences(applicationContext).edit() +            .putInt(Settings.PREF_CONTROL_SCALE, scale) +            .apply() +        emulationFragment!!.refreshInputOverlay() +    } + +    private fun resetOverlay() { +        MaterialAlertDialogBuilder(this) +            .setTitle(getString(R.string.emulation_touch_overlay_reset)) +            .setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> emulationFragment!!.resetInputOverlay() } +            .setNegativeButton(android.R.string.cancel, null) +            .create() +            .show() +    } + +    override fun dispatchTouchEvent(event: MotionEvent): Boolean { +        if (event.actionMasked == MotionEvent.ACTION_DOWN) { +            var anyMenuClosed = false +            var submenu = supportFragmentManager.findFragmentById(R.id.frame_submenu) +            if (submenu != null && areCoordinatesOutside(submenu.view, event.x, event.y)) { +                closeSubmenu() +                submenu = null +                anyMenuClosed = true +            } +            if (submenu == null) { +                val menu = supportFragmentManager.findFragmentById(R.id.frame_menu) +                if (menu != null && areCoordinatesOutside(menu.view, event.x, event.y)) { +                    closeMenu() +                    anyMenuClosed = true +                } +            } +            if (anyMenuClosed) { +                return true +            } +        } +        return super.dispatchTouchEvent(event) +    } + +    @Retention(AnnotationRetention.SOURCE) +    @IntDef( +        MENU_ACTION_EDIT_CONTROLS_PLACEMENT, +        MENU_ACTION_TOGGLE_CONTROLS, +        MENU_ACTION_ADJUST_SCALE, +        MENU_ACTION_EXIT, +        MENU_ACTION_SHOW_FPS, +        MENU_ACTION_RESET_OVERLAY, +        MENU_ACTION_SHOW_OVERLAY, +        MENU_ACTION_OPEN_SETTINGS +    ) +    annotation class MenuAction + +    private fun closeSubmenu(): Boolean { +        return supportFragmentManager.popBackStackImmediate( +            BACKSTACK_NAME_SUBMENU, +            FragmentManager.POP_BACK_STACK_INCLUSIVE +        ) +    } + +    private fun closeMenu(): Boolean { +        menuVisible = false +        return supportFragmentManager.popBackStackImmediate( +            BACKSTACK_NAME_MENU, +            FragmentManager.POP_BACK_STACK_INCLUSIVE +        ) +    } + +    private fun toggleMenu() { +        if (!closeMenu()) { +            val fragment: Fragment = MenuFragment.newInstance() +            supportFragmentManager.beginTransaction() +                .setCustomAnimations( +                    R.animator.menu_slide_in_from_start, +                    R.animator.menu_slide_out_to_start, +                    R.animator.menu_slide_in_from_start, +                    R.animator.menu_slide_out_to_start +                ) +                .add(R.id.frame_menu, fragment) +                .addToBackStack(BACKSTACK_NAME_MENU) +                .commit() +            menuVisible = true +        } +    } + +    companion object { +        private const val BACKSTACK_NAME_MENU = "menu" +        private const val BACKSTACK_NAME_SUBMENU = "submenu" +        const val EXTRA_SELECTED_GAME = "SelectedGame" +        const val EXTRA_SELECTED_TITLE = "SelectedTitle" +        const val MENU_ACTION_EDIT_CONTROLS_PLACEMENT = 0 +        const val MENU_ACTION_TOGGLE_CONTROLS = 1 +        const val MENU_ACTION_ADJUST_SCALE = 2 +        const val MENU_ACTION_EXIT = 3 +        const val MENU_ACTION_SHOW_FPS = 4 +        const val MENU_ACTION_RESET_OVERLAY = 6 +        const val MENU_ACTION_SHOW_OVERLAY = 7 +        const val MENU_ACTION_OPEN_SETTINGS = 8 +        private const val EMULATION_RUNNING_NOTIFICATION = 0x1000 + +        @JvmStatic +        fun launch(activity: FragmentActivity, path: String?, title: String?) { +            val launcher = Intent(activity, EmulationActivity::class.java) +            launcher.putExtra(EXTRA_SELECTED_GAME, path) +            launcher.putExtra(EXTRA_SELECTED_TITLE, title) +            activity.startActivity(launcher) +        } + +        @JvmStatic +        fun tryDismissRunningNotification(activity: Activity?) { +            // TODO(bunnei): Disable notifications until we support app suspension. +            //NotificationManagerCompat.from(activity).cancel(EMULATION_RUNNING_NOTIFICATION); +        } + +        private fun areCoordinatesOutside(view: View?, x: Float, y: Float): Boolean { +            if (view == null) { +                return true +            } +            val viewBounds = Rect() +            view.getGlobalVisibleRect(viewBounds) +            return !viewBounds.contains(x.roundToInt(), y.roundToInt()) +        } +    } +} | 
