ch.jeda.platform.android.CanvasFragment.java Source code

Java tutorial

Introduction

Here is the source code for ch.jeda.platform.android.CanvasFragment.java

Source

/*
 * Copyright (C) 2012 - 2015 by Stefan Rothe
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package ch.jeda.platform.android;

import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import ch.jeda.event.Event;
import ch.jeda.event.EventQueue;
import ch.jeda.event.EventType;
import ch.jeda.event.Key;
import ch.jeda.event.KeyEvent;
import ch.jeda.event.PointerEvent;
import ch.jeda.platform.ViewRequest;
import ch.jeda.ui.ViewFeature;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;

class CanvasFragment extends Fragment implements SurfaceHolder.Callback, View.OnKeyListener, View.OnTouchListener {

    private static final Map<Integer, EventSource> INPUT_DEVICE_MAP = new HashMap<Integer, EventSource>();
    private static final Map<Integer, Key> KEY_MAP = initKeyMap();
    private final EnumSet<ViewFeature> features;
    private EventQueue eventQueue;
    private ViewRequest request;
    private boolean surfaceAvailable;
    private SurfaceHolder surfaceHolder;

    CanvasFragment(final ViewRequest request) {
        super();
        this.features = request.getFeatures();
        this.request = request;
    }

    @Override
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
            final Bundle savedInstanceState) {
        final SurfaceView result = new SurfaceView(this.getActivity());
        result.setFocusable(true);
        result.setFocusableInTouchMode(true);
        result.setOnKeyListener(this);
        result.setOnTouchListener(this);
        this.surfaceHolder = result.getHolder();
        this.surfaceHolder.addCallback(this);
        return result;
    }

    @Override
    public boolean onKey(final View view, final int keyCode, final android.view.KeyEvent event) {
        final Key key = KEY_MAP.get(keyCode);
        if (key == null) {
            return false;
        }

        switch (event.getAction()) {
        case android.view.KeyEvent.ACTION_DOWN:
            this.postEvent(new KeyEvent(mapDevice(event), EventType.KEY_DOWN, key, event.getRepeatCount()));
            break;
        case android.view.KeyEvent.ACTION_UP:
            this.postEvent(new KeyEvent(mapDevice(event), EventType.KEY_UP, key));
            break;
        }

        return true;
    }

    @Override
    public boolean onTouch(final View view, final MotionEvent event) {
        int index;
        switch (event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_POINTER_DOWN:
            index = event.getActionIndex();
            this.postEvent(new PointerEvent(mapDevice(event), EventType.POINTER_DOWN, event.getPointerId(index),
                    (int) event.getX(index), (int) event.getY(index)));
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_POINTER_UP:
            index = event.getActionIndex();
            this.postEvent(new PointerEvent(mapDevice(event), EventType.POINTER_UP, event.getPointerId(index),
                    (int) event.getX(index), (int) event.getY(index)));
            break;
        case MotionEvent.ACTION_MOVE:
            for (index = 0; index < event.getPointerCount(); ++index) {
                this.postEvent(new PointerEvent(mapDevice(event), EventType.POINTER_MOVED,
                        event.getPointerId(index), (int) event.getX(index), (int) event.getY(index)));
            }

            break;
        }
        return true;
    }

    @Override
    public void surfaceCreated(final SurfaceHolder holder) {
        this.surfaceAvailable = true;
    }

    @Override
    public void surfaceChanged(final SurfaceHolder holder, final int format, final int width, final int height) {
        if (this.request != null) {
            this.request.setResult(AndroidViewImp.create(this, width, height));
            this.request = null;
        }
    }

    @Override
    public void surfaceDestroyed(final SurfaceHolder holder) {
        this.surfaceAvailable = false;
    }

    EnumSet<ViewFeature> getFeatures() {
        return this.features;
    }

    int getOrientation(final int currentOrientation) {
        if (this.features.contains(ViewFeature.ORIENTATION_LANDSCAPE)) {
            return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
        } else if (this.features.contains(ViewFeature.ORIENTATION_PORTRAIT)) {
            return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
        } else {
            return currentOrientation;
        }
    }

    void postEvent(final Event event) {
        if (this.eventQueue != null) {
            this.eventQueue.addEvent(event);
        }
    }

    void setBitmap(final Bitmap bitmap) {
        if (this.surfaceAvailable) {
            final Canvas canvas = this.surfaceHolder.lockCanvas();
            if (canvas != null) {
                canvas.drawBitmap(bitmap, 0f, 0f, null);
                this.surfaceHolder.unlockCanvasAndPost(canvas);
            }
        }
    }

    void setEventQueue(final EventQueue eventQueue) {
        this.eventQueue = eventQueue;
    }

    void setFeature(final ViewFeature feature, final boolean enabled) {
        if (enabled) {
            this.features.add(feature);
        } else {
            this.features.remove(feature);
        }
    }

    void setTitle(final String title) {
        this.getActivity().runOnUiThread(new Runnable() {
            public void run() {
                getActivity().setTitle(title);
            }
        });
    }

    private static Map<Integer, Key> initKeyMap() {
        final Map<Integer, Key> result = new HashMap();
        result.put(android.view.KeyEvent.KEYCODE_A, Key.A);
        result.put(android.view.KeyEvent.KEYCODE_ALT_LEFT, Key.ALT_LEFT);
        result.put(android.view.KeyEvent.KEYCODE_ALT_RIGHT, Key.ALT_RIGHT);
        result.put(android.view.KeyEvent.KEYCODE_APOSTROPHE, Key.APOSTROPHE);
        result.put(android.view.KeyEvent.KEYCODE_B, Key.B);
        result.put(android.view.KeyEvent.KEYCODE_BACKSLASH, Key.BACKSLASH);
        result.put(android.view.KeyEvent.KEYCODE_COMMA, Key.COMMA);
        // Android DEL key has the back space functionality
        result.put(android.view.KeyEvent.KEYCODE_DEL, Key.BACKSPACE);
        result.put(android.view.KeyEvent.KEYCODE_C, Key.C);
        result.put(android.view.KeyEvent.KEYCODE_D, Key.D);
        result.put(android.view.KeyEvent.KEYCODE_0, Key.DIGIT_0);
        result.put(android.view.KeyEvent.KEYCODE_1, Key.DIGIT_1);
        result.put(android.view.KeyEvent.KEYCODE_2, Key.DIGIT_2);
        result.put(android.view.KeyEvent.KEYCODE_3, Key.DIGIT_3);
        result.put(android.view.KeyEvent.KEYCODE_4, Key.DIGIT_4);
        result.put(android.view.KeyEvent.KEYCODE_5, Key.DIGIT_5);
        result.put(android.view.KeyEvent.KEYCODE_6, Key.DIGIT_6);
        result.put(android.view.KeyEvent.KEYCODE_7, Key.DIGIT_7);
        result.put(android.view.KeyEvent.KEYCODE_8, Key.DIGIT_8);
        result.put(android.view.KeyEvent.KEYCODE_9, Key.DIGIT_9);
        result.put(android.view.KeyEvent.KEYCODE_DPAD_DOWN, Key.DOWN);
        result.put(android.view.KeyEvent.KEYCODE_E, Key.E);
        result.put(android.view.KeyEvent.KEYCODE_ENTER, Key.ENTER);
        result.put(android.view.KeyEvent.KEYCODE_EQUALS, Key.EQUALS);
        result.put(android.view.KeyEvent.KEYCODE_F, Key.F);
        result.put(android.view.KeyEvent.KEYCODE_G, Key.G);
        result.put(android.view.KeyEvent.KEYCODE_GRAVE, Key.GRAVE);
        result.put(android.view.KeyEvent.KEYCODE_H, Key.H);
        result.put(android.view.KeyEvent.KEYCODE_I, Key.I);
        result.put(android.view.KeyEvent.KEYCODE_J, Key.J);
        result.put(android.view.KeyEvent.KEYCODE_K, Key.K);
        result.put(android.view.KeyEvent.KEYCODE_L, Key.L);
        result.put(android.view.KeyEvent.KEYCODE_DPAD_LEFT, Key.LEFT);
        result.put(android.view.KeyEvent.KEYCODE_M, Key.M);
        result.put(android.view.KeyEvent.KEYCODE_MENU, Key.MENU);
        result.put(android.view.KeyEvent.KEYCODE_MINUS, Key.MINUS);
        result.put(android.view.KeyEvent.KEYCODE_N, Key.N);
        result.put(android.view.KeyEvent.KEYCODE_O, Key.O);
        result.put(android.view.KeyEvent.KEYCODE_P, Key.P);
        result.put(android.view.KeyEvent.KEYCODE_PAGE_DOWN, Key.PAGE_DOWN);
        result.put(android.view.KeyEvent.KEYCODE_PAGE_UP, Key.PAGE_UP);
        result.put(android.view.KeyEvent.KEYCODE_PERIOD, Key.PERIOD);
        result.put(android.view.KeyEvent.KEYCODE_Q, Key.Q);
        result.put(android.view.KeyEvent.KEYCODE_R, Key.R);
        result.put(android.view.KeyEvent.KEYCODE_DPAD_RIGHT, Key.RIGHT);
        result.put(android.view.KeyEvent.KEYCODE_S, Key.S);
        result.put(android.view.KeyEvent.KEYCODE_SHIFT_LEFT, Key.SHIFT_LEFT);
        result.put(android.view.KeyEvent.KEYCODE_SHIFT_RIGHT, Key.SHIFT_RIGHT);
        result.put(android.view.KeyEvent.KEYCODE_SLASH, Key.SLASH);
        result.put(android.view.KeyEvent.KEYCODE_SPACE, Key.SPACE);
        result.put(android.view.KeyEvent.KEYCODE_T, Key.T);
        result.put(android.view.KeyEvent.KEYCODE_TAB, Key.TAB);
        result.put(android.view.KeyEvent.KEYCODE_U, Key.U);
        result.put(android.view.KeyEvent.KEYCODE_DPAD_UP, Key.UP);
        result.put(android.view.KeyEvent.KEYCODE_V, Key.V);
        result.put(android.view.KeyEvent.KEYCODE_VOLUME_DOWN, Key.VOLUME_DOWN);
        result.put(android.view.KeyEvent.KEYCODE_VOLUME_UP, Key.VOLUME_UP);
        result.put(android.view.KeyEvent.KEYCODE_W, Key.W);
        result.put(android.view.KeyEvent.KEYCODE_X, Key.X);
        result.put(android.view.KeyEvent.KEYCODE_Y, Key.Y);
        result.put(android.view.KeyEvent.KEYCODE_Z, Key.Z);

        // Not supported
        //        result.put(android.view.KeyEvent.KEYCODE_, Key.END);
        //        result.put(android.view.KeyEvent.KEYCODE_, Key.HOME);
        //        result.put(android.view.KeyEvent.KEYCODE_, Key.PAUSE);
        //        result.put(android.view.KeyEvent.KEYCODE_, Key.PRINT_SCREEN);
        //        result.put(android.view.KeyEvent.KEYCODE_, Key.INSERT);
        //        result.put(android.view.KeyEvent.KEYCODE_, Key.DELETE);
        // Only since API level 11
        //        result.put(android.view.KeyEvent.KEYCODE_ALT_GRAPH, Key.ALT_GRAPH);
        //        result.put(android.view.KeyEvent.KEYCODE_CAPS_LOCK, Key.CAPS_LOCK);
        //        result.put(android.view.KeyEvent.KEYCODE_CTRL_LEFT, Key.CONTROL_LEFT);
        //        result.put(android.view.KeyEvent.KEYCODE_CTRL_RIGHT, Key.CONTROL_RIGHT);
        //        result.put(android.view.KeyEvent.KEYCODE_ESCAPE, Key.ESCAPE);
        //        result.put(android.view.KeyEvent.KEYCODE_F1, Key.F1);
        //        result.put(android.view.KeyEvent.KEYCODE_F2, Key.F2);
        //        result.put(android.view.KeyEvent.KEYCODE_F3, Key.F3);
        //        result.put(android.view.KeyEvent.KEYCODE_F4, Key.F4);
        //        result.put(android.view.KeyEvent.KEYCODE_F5, Key.F5);
        //        result.put(android.view.KeyEvent.KEYCODE_F6, Key.F6);
        //        result.put(android.view.KeyEvent.KEYCODE_F7, Key.F7);
        //        result.put(android.view.KeyEvent.KEYCODE_F8, Key.F8);
        //        result.put(android.view.KeyEvent.KEYCODE_F9, Key.F9);
        //        result.put(android.view.KeyEvent.KEYCODE_F10, Key.F10);
        //        result.put(android.view.KeyEvent.KEYCODE_F11, Key.F11);
        //        result.put(android.view.KeyEvent.KEYCODE_F12, Key.F12);
        //        result.put(android.view.KeyEvent.KEYCODE_NUM_LOCK, Key.NUM_LOCK);
        //        result.put(android.view.KeyEvent.KEYCODE_NUMPAD_0, Key.NUMPAD_0);
        //        result.put(android.view.KeyEvent.KEYCODE_NUMPAD_1, Key.NUMPAD_1);
        //        result.put(android.view.KeyEvent.KEYCODE_NUMPAD_2, Key.NUMPAD_2);
        //        result.put(android.view.KeyEvent.KEYCODE_NUMPAD_3, Key.NUMPAD_3);
        //        result.put(android.view.KeyEvent.KEYCODE_NUMPAD_4, Key.NUMPAD_4);
        //        result.put(android.view.KeyEvent.KEYCODE_NUMPAD_5, Key.NUMPAD_5);
        //        result.put(android.view.KeyEvent.KEYCODE_NUMPAD_6, Key.NUMPAD_6);
        //        result.put(android.view.KeyEvent.KEYCODE_NUMPAD_7, Key.NUMPAD_7);
        //        result.put(android.view.KeyEvent.KEYCODE_NUMPAD_8, Key.NUMPAD_8);
        //        result.put(android.view.KeyEvent.KEYCODE_NUMPAD_9, Key.NUMPAD_9);
        //        result.put(android.view.KeyEvent.KEYCODE_NUMPAD_ADD, Key.NUMPAD_ADD);
        //        result.put(android.view.KeyEvent.KEYCODE_NUMPAD_DIVIDE, Key.NUMPAD_DIVIDE);
        //        result.put(android.view.KeyEvent.KEYCODE_NUMPAD_DOT, Key.NUMPAD_DOT);
        //        result.put(android.view.KeyEvent.KEYCODE_NUMPAD_ENTER, Key.NUMPAD_ENTER);
        //        result.put(android.view.KeyEvent.KEYCODE_NUMPAD_MULTIPLY, Key.NUMPAD_MULTIPLY);
        //        result.put(android.view.KeyEvent.KEYCODE_NUMPAD_SUBTRACT, Key.NUMPAD_SUBTRACT);
        //        result.put(android.view.KeyEvent.KEYCODE_SCROLL_LOCK, Key.SCROLL_LOCK);
        return result;
    }

    private static EventSource mapDevice(final android.view.InputEvent event) {
        final android.view.InputDevice device = event.getDevice();
        final int id = device.getId();
        if (!INPUT_DEVICE_MAP.containsKey(id)) {
            INPUT_DEVICE_MAP.put(id, new EventSource(device.getName()));
        }

        return INPUT_DEVICE_MAP.get(id);
    }

    private static class EventSource {

        private final String name;

        public EventSource(final String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return this.name;
        }
    }
}