diff --git a/app-android/app/build.gradle b/app-android/app/build.gradle index bab7253..6cc8923 100644 --- a/app-android/app/build.gradle +++ b/app-android/app/build.gradle @@ -19,5 +19,5 @@ android { } dependencies { - compile "com.android.support:appcompat-v7:21.0.+" + compile "com.android.support:appcompat-v7:22.+" } diff --git a/app-android/app/src/main/AndroidManifest.xml b/app-android/app/src/main/AndroidManifest.xml index 8e883cb..eaa6569 100644 --- a/app-android/app/src/main/AndroidManifest.xml +++ b/app-android/app/src/main/AndroidManifest.xml @@ -4,9 +4,7 @@ android:versionCode="4" android:versionName="1.3" > - + @@ -18,7 +16,8 @@ android:allowBackup="true" android:icon="@drawable/ic_launcher" android:theme="@style/AppTheme" - android:label="@string/app_name" > + android:label="@string/app_name" + android:largeHeap="true"> = 16) uiFlags ^= View.SYSTEM_UI_FLAG_FULLSCREEN; - if (Build.VERSION.SDK_INT >= 18) + if (Build.VERSION.SDK_INT >= 19) uiFlags ^= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; decorView.setOnSystemUiVisibilityChangeListener(this); @@ -106,16 +130,21 @@ public class CanvasActivity extends ActionBarActivity implements View.OnSystemUi @Override public void onSystemUiVisibilityChange(int visibility) { + Log.i("GfxTablet", "System UI changed " + visibility); + + fullScreen = (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0; + // show/hide action bar according to full-screen mode - if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0) { + if (fullScreen) { CanvasActivity.this.getSupportActionBar().hide(); - fullScreen = true; Toast.makeText(CanvasActivity.this, "Press Back button to leave full-screen mode.", Toast.LENGTH_LONG).show(); } else CanvasActivity.this.getSupportActionBar().show(); } + // template image logic + private String getTemplateImagePath() { return preferences.getString(SettingsActivity.KEY_TEMPLATE_IMAGE, null); } @@ -143,6 +172,7 @@ public class CanvasActivity extends ActionBarActivity implements View.OnSystemUi @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && data != null) { Uri selectedImage = data.getData(); String[] filePathColumn = { MediaStore.Images.Media.DATA }; @@ -159,32 +189,41 @@ public class CanvasActivity extends ActionBarActivity implements View.OnSystemUi } finally { cursor.close(); } - } else - super.onActivityResult(requestCode, resultCode, data); + } } public void showTemplateImage() { - String picturePath = preferences.getString(SettingsActivity.KEY_TEMPLATE_IMAGE, null); - if (picturePath != null) { - Drawable drawable = BitmapDrawable.createFromPath(picturePath); - getWindow().setBackgroundDrawable(drawable); - } else - getWindow().setBackgroundDrawableResource(android.R.drawable.screen_background_light); + ImageView template = (ImageView)findViewById(R.id.canvas_template); + template.setImageDrawable(null); + + if (template.getVisibility() == View.VISIBLE) { + String picturePath = preferences.getString(SettingsActivity.KEY_TEMPLATE_IMAGE, null); + if (picturePath != null) + try { + // TODO load bitmap efficiently, for intended view size and display resolution + // https://developer.android.com/training/displaying-bitmaps/load-bitmap.html + final Drawable drawable = new BitmapDrawable(getResources(), picturePath); + template.setImageDrawable(drawable); + } catch (Exception e) { + Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show(); + } + } } private class ConfigureNetworkingTask extends AsyncTask { @Override protected Boolean doInBackground(Void... params) { - return netClient.configureNetworking(); + return netClient.reconfigureNetworking(); } protected void onPostExecute(Boolean success) { - if (success) { - setContentView(canvas); + if (success) Toast.makeText(CanvasActivity.this, "Touch events will be sent to " + netClient.destAddress.getHostAddress() + ":" + NetworkClient.GFXTABLET_PORT, Toast.LENGTH_LONG).show(); - } else - setContentView(R.layout.activity_no_host); + + findViewById(R.id.canvas_template).setVisibility(success ? View.VISIBLE : View.GONE); + findViewById(R.id.canvas).setVisibility(success ? View.VISIBLE : View.GONE); + findViewById(R.id.canvas_message).setVisibility(success ? View.GONE : View.VISIBLE); } } diff --git a/app-android/app/src/main/java/at/bitfire/gfxtablet/CanvasView.java b/app-android/app/src/main/java/at/bitfire/gfxtablet/CanvasView.java index a1866b8..74c72d1 100644 --- a/app-android/app/src/main/java/at/bitfire/gfxtablet/CanvasView.java +++ b/app-android/app/src/main/java/at/bitfire/gfxtablet/CanvasView.java @@ -5,6 +5,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.graphics.Color; import android.preference.PreferenceManager; +import android.support.annotation.NonNull; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; @@ -13,32 +14,63 @@ import android.view.View; import at.bitfire.gfxtablet.NetEvent.Type; @SuppressLint("ViewConstructor") -public class CanvasView extends View { +public class CanvasView extends View implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = "GfxTablet.CanvasView"; final SharedPreferences settings; - final NetworkClient netClient; + NetworkClient netClient; boolean acceptStylusOnly; int maxX, maxY; - public CanvasView(Context context, NetworkClient networkClient) { - super(context); - this.netClient = networkClient; - // process preferences + // setup + + public CanvasView(Context context, AttributeSet attributeSet) { + super(context, attributeSet); + + // view is disabled until a network client is set + setEnabled(false); + settings = PreferenceManager.getDefaultSharedPreferences(context); - acceptStylusOnly = settings.getBoolean(SettingsActivity.KEY_PREF_STYLUS_ONLY, false); + settings.registerOnSharedPreferenceChangeListener(this); + setBackground(); + setInputMethods(); } - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); + public void setNetworkClient(NetworkClient networkClient) { + netClient = networkClient; + setEnabled(true); + } + + + // settings + + protected void setBackground() { if (settings.getBoolean(SettingsActivity.KEY_DARK_CANVAS, false)) setBackgroundColor(Color.BLACK); else setBackgroundResource(R.drawable.bg_grid_pattern); } + protected void setInputMethods() { + acceptStylusOnly = settings.getBoolean(SettingsActivity.KEY_PREF_STYLUS_ONLY, false); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + switch (key) { + case SettingsActivity.KEY_PREF_STYLUS_ONLY: + setInputMethods(); + break; + case SettingsActivity.KEY_DARK_CANVAS: + setBackground(); + break; + } + } + + + // drawing + @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { Log.i(TAG, "Canvas size changed: " + w + "x" + h + " (before: " + oldw + "x" + oldh + ")"); @@ -65,7 +97,7 @@ public class CanvasView extends View { } @Override - public boolean onTouchEvent(MotionEvent event) { + public boolean onTouchEvent(@NonNull MotionEvent event) { if (isEnabled()) { for (int ptr = 0; ptr < event.getPointerCount(); ptr++) if (!acceptStylusOnly || (event.getToolType(ptr) == MotionEvent.TOOL_TYPE_STYLUS)) { @@ -104,4 +136,5 @@ public class CanvasView extends View { short normalizePressure(float x) { return (short)(Math.min(Math.max(0, x), 2.0) * Short.MAX_VALUE/2.0); } + } diff --git a/app-android/app/src/main/java/at/bitfire/gfxtablet/NetworkClient.java b/app-android/app/src/main/java/at/bitfire/gfxtablet/NetworkClient.java index ad7e04d..c437725 100644 --- a/app-android/app/src/main/java/at/bitfire/gfxtablet/NetworkClient.java +++ b/app-android/app/src/main/java/at/bitfire/gfxtablet/NetworkClient.java @@ -13,19 +13,19 @@ import at.bitfire.gfxtablet.NetEvent.Type; public class NetworkClient implements Runnable { - static int GFXTABLET_PORT = 40118; + static final int GFXTABLET_PORT = 40118; - LinkedBlockingQueue motionQueue = new LinkedBlockingQueue<>(); + final LinkedBlockingQueue motionQueue = new LinkedBlockingQueue<>(); LinkedBlockingQueue getQueue() { return motionQueue; } InetAddress destAddress; - SharedPreferences preferences; + final SharedPreferences preferences; NetworkClient(SharedPreferences preferences) { this.preferences = preferences; } - boolean configureNetworking() { + boolean reconfigureNetworking() { try { String hostName = preferences.getString(SettingsActivity.KEY_PREF_HOST, "unknown.invalid"); destAddress = InetAddress.getByName(hostName); diff --git a/app-android/app/src/main/java/at/bitfire/gfxtablet/SettingsActivity.java b/app-android/app/src/main/java/at/bitfire/gfxtablet/SettingsActivity.java index 29baea8..d81257b 100644 --- a/app-android/app/src/main/java/at/bitfire/gfxtablet/SettingsActivity.java +++ b/app-android/app/src/main/java/at/bitfire/gfxtablet/SettingsActivity.java @@ -1,10 +1,10 @@ package at.bitfire.gfxtablet; -import android.app.Activity; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; +import android.support.v7.app.AppCompatActivity; -public class SettingsActivity extends ActionBarActivity { +public class SettingsActivity extends AppCompatActivity { public static final String KEY_PREF_HOST = "host_preference", KEY_PREF_STYLUS_ONLY = "stylus_only_preference", diff --git a/app-android/app/src/main/res/drawable-hdpi/ic_action_picture.png b/app-android/app/src/main/res/drawable-hdpi/ic_action_picture.png new file mode 100644 index 0000000..00216ea Binary files /dev/null and b/app-android/app/src/main/res/drawable-hdpi/ic_action_picture.png differ diff --git a/app-android/app/src/main/res/drawable-mdpi/ic_action_picture.png b/app-android/app/src/main/res/drawable-mdpi/ic_action_picture.png index 3fb1134..5c994c6 100644 Binary files a/app-android/app/src/main/res/drawable-mdpi/ic_action_picture.png and b/app-android/app/src/main/res/drawable-mdpi/ic_action_picture.png differ diff --git a/app-android/app/src/main/res/drawable-xhdpi/ic_action_picture.png b/app-android/app/src/main/res/drawable-xhdpi/ic_action_picture.png index a41fb71..28506b2 100644 Binary files a/app-android/app/src/main/res/drawable-xhdpi/ic_action_picture.png and b/app-android/app/src/main/res/drawable-xhdpi/ic_action_picture.png differ diff --git a/app-android/app/src/main/res/drawable-xxhdpi/ic_action_picture.png b/app-android/app/src/main/res/drawable-xxhdpi/ic_action_picture.png index eeb5a8f..b81237f 100644 Binary files a/app-android/app/src/main/res/drawable-xxhdpi/ic_action_picture.png and b/app-android/app/src/main/res/drawable-xxhdpi/ic_action_picture.png differ diff --git a/app-android/app/src/main/res/layout/activity_canvas.xml b/app-android/app/src/main/res/layout/activity_canvas.xml new file mode 100644 index 0000000..4f3ee16 --- /dev/null +++ b/app-android/app/src/main/res/layout/activity_canvas.xml @@ -0,0 +1,29 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app-android/app/src/main/res/layout/activity_no_host.xml b/app-android/app/src/main/res/layout/activity_no_host.xml deleted file mode 100644 index 88f43b7..0000000 --- a/app-android/app/src/main/res/layout/activity_no_host.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app-android/app/src/main/res/layout/activity_settings.xml b/app-android/app/src/main/res/layout/activity_settings.xml index d4023ec..05060f7 100644 --- a/app-android/app/src/main/res/layout/activity_settings.xml +++ b/app-android/app/src/main/res/layout/activity_settings.xml @@ -1,12 +1,15 @@ - + - \ No newline at end of file + android:name="at.bitfire.gfxtablet.SettingsFragment" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center_horizontal|top" + tools:layout="@layout/activity_settings"/> + \ No newline at end of file diff --git a/app-android/app/src/main/res/menu/activity_canvas.xml b/app-android/app/src/main/res/menu/activity_canvas.xml index 01a1e19..4fac79f 100644 --- a/app-android/app/src/main/res/menu/activity_canvas.xml +++ b/app-android/app/src/main/res/menu/activity_canvas.xml @@ -1,20 +1,20 @@ - + + app:showAsAction="ifRoom" + android:title="@string/menu_set_template_image"/> + app:showAsAction="ifRoom" + android:title="@string/fullscreen"/> + + \ No newline at end of file diff --git a/app-android/app/src/main/res/menu/set_template_image.xml b/app-android/app/src/main/res/menu/set_template_image.xml index f1f8509..8b10198 100644 --- a/app-android/app/src/main/res/menu/set_template_image.xml +++ b/app-android/app/src/main/res/menu/set_template_image.xml @@ -4,11 +4,11 @@ + android:title="@string/menu_clear_template_image"/> + android:title="@string/menu_select_another_template_image"/> \ No newline at end of file diff --git a/app-android/app/src/main/res/values/strings.xml b/app-android/app/src/main/res/values/strings.xml index 5036642..7b35d63 100644 --- a/app-android/app/src/main/res/values/strings.xml +++ b/app-android/app/src/main/res/values/strings.xml @@ -4,6 +4,12 @@ GfxTablet Settings About / Help + Donate + + Full-screen mode + Set template image + Clear template image + Select another image No valid recipient host defined. Please configure in \"Settings / Recipient host\". @@ -13,8 +19,8 @@ Only stylus input will be processed Finger and stylus input will be processed Use dark canvas - Black canvas will be used - White canvas will be used + Black canvas will be used (covers template image) + White/transparent gridded canvas will be used Keep display active Display won\'t turn off while GfxTablet is active Display will turn off according to system settings diff --git a/app-android/app/src/main/res/xml/preferences.xml b/app-android/app/src/main/res/xml/preferences.xml index 88c4254..a5b2e74 100644 --- a/app-android/app/src/main/res/xml/preferences.xml +++ b/app-android/app/src/main/res/xml/preferences.xml @@ -1,7 +1,7 @@