diff --git a/Source/Android/app/build.gradle b/Source/Android/app/build.gradle index d6a3aac6ba..3cdbade125 100644 --- a/Source/Android/app/build.gradle +++ b/Source/Android/app/build.gradle @@ -9,6 +9,10 @@ android { // This is important as it will run lint but not abort on error // Lint has some overly obnoxious "errors" that should really be warnings abortOnError false + + //Uncomment disable lines for test builds... + //disable 'MissingTranslation' + //disable 'ExtraTranslation' } defaultConfig { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index b11e7cbd8c..cb52090c47 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -394,6 +394,18 @@ public final class EmulationActivity extends AppCompatActivity return; } + case R.id.menu_emulation_configure_controls: + EmulationFragment emulationFragment = (EmulationFragment) getFragmentManager().findFragmentById(R.id.frame_emulation_fragment); + if(emulationFragment.isConfiguringControls()) + { + emulationFragment.stopConfiguringControls(); + } + else + { + emulationFragment.startConfiguringControls(); + } + break; + case R.id.menu_refresh_wiimotes: NativeLibrary.RefreshWiimotes(); return; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java index 4fad5256bb..8665c64715 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java @@ -10,6 +10,7 @@ import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; +import android.widget.Button; import org.dolphinemu.dolphinemu.BuildConfig; import org.dolphinemu.dolphinemu.NativeLibrary; @@ -86,7 +87,6 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C } } - if (savedInstanceState == null) { mEmulationThread = new Thread(mEmulationRunner); @@ -101,6 +101,17 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C return contents; } + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + Button doneButton = (Button) view.findViewById(R.id.done_control_config); + doneButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + stopConfiguringControls(); + } + }); + } + @Override public void onStart() { @@ -224,4 +235,19 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C NativeLibrary.Run(); } }; + + public void startConfiguringControls() + { + getView().findViewById(R.id.done_control_config).setVisibility(View.VISIBLE); + mInputOverlay.setIsInEditMode(true); + } + + public void stopConfiguringControls() { + getView().findViewById(R.id.done_control_config).setVisibility(View.GONE); + mInputOverlay.setIsInEditMode(false); + } + + public boolean isConfiguringControls() { + return mInputOverlay.isInEditMode(); + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java index 2617491890..d42406c9e6 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java @@ -39,6 +39,10 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener private final Set overlayButtons = new HashSet<>(); private final Set overlayJoysticks = new HashSet<>(); + private boolean mIsInEditMode = false; + private InputOverlayDrawableButton mButtonBeingConfigured; + private InputOverlayDrawableJoystick mJoystickBeingConfigured; + /** * Resizes a {@link Bitmap} by a given scale factor * @@ -111,6 +115,10 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener @Override public boolean onTouch(View v, MotionEvent event) { + if(isInEditMode()) { + return onTouchWhileEditing(v, event); + } + int pointerIndex = event.getActionIndex(); for (InputOverlayDrawableButton button : overlayButtons) @@ -148,6 +156,95 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener return true; } + public boolean onTouchWhileEditing(View v, MotionEvent event) + { + int pointerIndex = event.getActionIndex(); + int fingerPositionX = (int)event.getX(pointerIndex); + int fingerPositionY = (int)event.getY(pointerIndex); + + //Maybe combine Button and Joystick as subclasses of the same parent? + //Or maybe create an interface like IMoveableHUDControl? + + for (InputOverlayDrawableButton button : overlayButtons) + { + // Determine the button state to apply based on the MotionEvent action flag. + switch(event.getAction() & MotionEvent.ACTION_MASK) + { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + // If no button is being moved now, remember the currently touched button to move. + if(mButtonBeingConfigured == null && button.getBounds().contains(fingerPositionX, fingerPositionY)) + { + mButtonBeingConfigured = button; + mButtonBeingConfigured.onConfigureTouch(v, event); + } + break; + case MotionEvent.ACTION_MOVE: + if (mButtonBeingConfigured != null) + { + mButtonBeingConfigured.onConfigureTouch(v, event); + invalidate(); + return true; + } + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + if(mButtonBeingConfigured == button) + { + //Persist button position by saving new place. + saveControlPosition(mButtonBeingConfigured.getSharedPrefsId(), mButtonBeingConfigured.getBounds().left, mButtonBeingConfigured.getBounds().top); + mButtonBeingConfigured = null; + } + break; + } + } + + + for (InputOverlayDrawableJoystick joystick : overlayJoysticks) + { + switch(event.getAction()) + { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + if(mJoystickBeingConfigured == null && joystick.getBounds().contains(fingerPositionX, fingerPositionY)) + { + mJoystickBeingConfigured = joystick; + mJoystickBeingConfigured.onConfigureTouch(v, event); + } + break; + case MotionEvent.ACTION_MOVE: + if(mJoystickBeingConfigured != null) + { + mJoystickBeingConfigured.onConfigureTouch(v, event); + invalidate(); + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + if(mJoystickBeingConfigured != null) + { + saveControlPosition(mJoystickBeingConfigured.getSharedPrefsId(), mJoystickBeingConfigured.getBounds().left, mJoystickBeingConfigured.getBounds().right); + mJoystickBeingConfigured = null; + } + break; + + } + } + + + return true; + } + + private void saveControlPosition(String sharedPrefsId, int x, int y) + { + final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); + SharedPreferences.Editor sPrefsEditor = sPrefs.edit(); + sPrefsEditor.putFloat(sharedPrefsId+"-X", x); + sPrefsEditor.putFloat(sharedPrefsId+"-Y", y); + sPrefsEditor.apply(); + } + /** * Initializes an InputOverlayDrawableButton, given by resId, with all of the * parameters set for it to be properly shown on the InputOverlay. @@ -212,11 +309,10 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener // Initialize the InputOverlayDrawableButton. final Bitmap bitmap = resizeBitmap(context, BitmapFactory.decodeResource(res, resId), scale); - final InputOverlayDrawableButton overlayDrawable = new InputOverlayDrawableButton(res, bitmap, buttonId); - // String ID of the Drawable. This is what is passed into SharedPreferences - // to check whether or not a value has been set. + // to check whether or not a value has been set. Send to button so it can be referenced. final String drawableId = res.getResourceEntryName(resId); + final InputOverlayDrawableButton overlayDrawable = new InputOverlayDrawableButton(res, bitmap, buttonId, drawableId); // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. // These were set in the input overlay configuration menu. @@ -233,6 +329,9 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener // This will dictate where on the screen (and the what the size) the InputOverlayDrawableButton will be. overlayDrawable.setBounds(drawableX, drawableY, drawableX+intrinWidth, drawableY+intrinHeight); + // Need to set the image's position + overlayDrawable.setPosition(drawableX, drawableY); + return overlayDrawable; } @@ -276,14 +375,26 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener Rect outerRect = new Rect(drawableX, drawableY, drawableX + outerSize, drawableY + outerSize); Rect innerRect = new Rect(0, 0, outerSize / 4, outerSize / 4); + // Send the drawableId to the joystick so it can be referenced when saving control position. final InputOverlayDrawableJoystick overlayDrawable = new InputOverlayDrawableJoystick(res, bitmapOuter, bitmapInner, outerRect, innerRect, - joystick); + joystick, drawableId); + // Need to set the image's position + overlayDrawable.setPosition(drawableX, drawableY); return overlayDrawable; } + + public void setIsInEditMode(boolean isInEditMode) + { + mIsInEditMode = isInEditMode; + } + + public boolean isInEditMode() { + return mIsInEditMode; + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableButton.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableButton.java index e02e352e56..add3cf4621 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableButton.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableButton.java @@ -8,7 +8,10 @@ package org.dolphinemu.dolphinemu.overlay; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; +import android.view.MotionEvent; +import android.view.View; /** * Custom {@link BitmapDrawable} that is capable @@ -17,7 +20,10 @@ import android.graphics.drawable.BitmapDrawable; public final class InputOverlayDrawableButton extends BitmapDrawable { // The ID identifying what type of button this Drawable represents. - private int buttonType; + private int mButtonType; + private int mPreviousTouchX, mPreviousTouchY; + private int mControlPositionX, mControlPositionY; + private String mSharedPrefsId; /** * Constructor @@ -25,12 +31,13 @@ public final class InputOverlayDrawableButton extends BitmapDrawable * @param res {@link Resources} instance. * @param bitmap {@link Bitmap} to use with this Drawable. * @param buttonType Identifier for this type of button. + * @param sharedPrefsId Identifier for getting X and Y control positions from Shared Preferences. */ - public InputOverlayDrawableButton(Resources res, Bitmap bitmap, int buttonType) + public InputOverlayDrawableButton(Resources res, Bitmap bitmap, int buttonType, String sharedPrefsId) { super(res, bitmap); - - this.buttonType = buttonType; + mButtonType = buttonType; + mSharedPrefsId = sharedPrefsId; } /** @@ -40,6 +47,40 @@ public final class InputOverlayDrawableButton extends BitmapDrawable */ public int getId() { - return buttonType; + return mButtonType; + } + + public boolean onConfigureTouch(View v, MotionEvent event) + { + int pointerIndex = event.getActionIndex(); + int fingerPositionX = (int)event.getX(pointerIndex); + int fingerPositionY = (int)event.getY(pointerIndex); + switch (event.getAction()) + { + case MotionEvent.ACTION_DOWN: + mPreviousTouchX = fingerPositionX; + mPreviousTouchY = fingerPositionY; + break; + case MotionEvent.ACTION_MOVE: + mControlPositionX += fingerPositionX - mPreviousTouchX; + mControlPositionY += fingerPositionY - mPreviousTouchY; + setBounds(new Rect(mControlPositionX, mControlPositionY, getBitmap().getWidth() + mControlPositionX, getBitmap().getHeight() + mControlPositionY)); + mPreviousTouchX = fingerPositionX; + mPreviousTouchY = fingerPositionY; + break; + + } + return true; + } + + public String getSharedPrefsId() + { + return mSharedPrefsId; + } + + public void setPosition(int x, int y) + { + mControlPositionX = x; + mControlPositionY = y; } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.java index d4082e4289..56ac768a5a 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.java @@ -12,6 +12,7 @@ import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.view.MotionEvent; +import android.view.View; /** * Custom {@link BitmapDrawable} that is capable @@ -23,6 +24,9 @@ public final class InputOverlayDrawableJoystick extends BitmapDrawable private final float[] axises = {0f, 0f}; private final BitmapDrawable ringInner; private int trackId = -1; + private String mSharedPrefsId; + private int mControlPositionX, mControlPositionY; + private int mPreviousTouchX, mPreviousTouchY; /** * Constructor @@ -33,11 +37,12 @@ public final class InputOverlayDrawableJoystick extends BitmapDrawable * @param rectOuter {@link Rect} which represents the outer joystick bounds. * @param rectInner {@link Rect} which represents the inner joystick bounds. * @param joystick Identifier for which joystick this is. + * @param sharedPrefsId Identifier for getting X and Y control positions from Shared Preferences. */ public InputOverlayDrawableJoystick(Resources res, Bitmap bitmapOuter, Bitmap bitmapInner, Rect rectOuter, Rect rectInner, - int joystick) + int joystick, String sharedPrefsId) { super(res, bitmapOuter); this.setBounds(rectOuter); @@ -49,13 +54,13 @@ public final class InputOverlayDrawableJoystick extends BitmapDrawable this.axisIDs[1] = joystick + 2; this.axisIDs[2] = joystick + 3; this.axisIDs[3] = joystick + 4; + mSharedPrefsId = sharedPrefsId; } @Override public void draw(Canvas canvas) { super.draw(canvas); - ringInner.draw(canvas); } @@ -106,6 +111,33 @@ public final class InputOverlayDrawableJoystick extends BitmapDrawable } } + public boolean onConfigureTouch(View v, MotionEvent event) + { + int pointerIndex = event.getActionIndex(); + int fingerPositionX = (int)event.getX(pointerIndex); + int fingerPositionY = (int)event.getY(pointerIndex); + switch (event.getAction()) + { + case MotionEvent.ACTION_DOWN: + mPreviousTouchX = fingerPositionX; + mPreviousTouchY = fingerPositionY; + break; + case MotionEvent.ACTION_MOVE: + int deltaX = fingerPositionX - mPreviousTouchX; + int deltaY = fingerPositionY - mPreviousTouchY; + mControlPositionX += deltaX; + mControlPositionY += deltaY; + setBounds(new Rect(mControlPositionX, mControlPositionY, getBitmap().getWidth() + mControlPositionX, getBitmap().getHeight() + mControlPositionY)); + SetInnerBounds(); + mPreviousTouchX = fingerPositionX; + mPreviousTouchY = fingerPositionY; + break; + + } + return true; + } + + public float[] getAxisValues() { float[] joyaxises = {0f, 0f, 0f, 0f}; @@ -133,5 +165,17 @@ public final class InputOverlayDrawableJoystick extends BitmapDrawable int height = this.ringInner.getBounds().height() / 2; this.ringInner.setBounds(X - width, Y - height, X + width, Y + height); + ringInner.invalidateSelf(); + } + + public String getSharedPrefsId() + { + return mSharedPrefsId; + } + + public void setPosition(int x, int y) + { + mControlPositionX = x; + mControlPositionY = y; } } diff --git a/Source/Android/app/src/main/res/layout/fragment_emulation.xml b/Source/Android/app/src/main/res/layout/fragment_emulation.xml index 28f51b2412..2ba3186324 100644 --- a/Source/Android/app/src/main/res/layout/fragment_emulation.xml +++ b/Source/Android/app/src/main/res/layout/fragment_emulation.xml @@ -20,4 +20,16 @@ android:layout_width="match_parent" android:focusable="true" android:focusableInTouchMode="true"/> + +