From a497955836dfe4d1bf09b2c7510b663ac066d9f2 Mon Sep 17 00:00:00 2001 From: vanitasvitae Date: Fri, 15 Sep 2017 00:55:43 +0200 Subject: [PATCH 1/6] Fix NPE --- .../spherical/parser/PhotoSphereParser.java | 25 ++++++++++++++----- app/src/main/res/values-v21/styles.xml | 2 ++ 2 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 app/src/main/res/values-v21/styles.xml diff --git a/app/src/main/java/de/trac/spherical/parser/PhotoSphereParser.java b/app/src/main/java/de/trac/spherical/parser/PhotoSphereParser.java index 79c529a..4e0fa78 100644 --- a/app/src/main/java/de/trac/spherical/parser/PhotoSphereParser.java +++ b/app/src/main/java/de/trac/spherical/parser/PhotoSphereParser.java @@ -169,32 +169,45 @@ public class PhotoSphereParser { private static Integer parseInteger(String key, String xmp, Integer defaultValue) { String value = parseString(key, xmp); - return value == null ? defaultValue : Integer.parseInt(value); + if (value == null) { + return defaultValue; + } + return Integer.parseInt(value); + } private static Float parseFloat(String key, String xmp, Float defaultValue) { String value = parseString(key, xmp); if (value == null) { return defaultValue; - } else { - return Float.parseFloat(value); } + return Float.parseFloat(value); + } private static Boolean parseBoolean(String key, String xmp, Boolean defaultValue) { String value = parseString(key, xmp); - return value == null ? defaultValue : Boolean.parseBoolean(value); + if (value == null) { + return defaultValue; + } + return Boolean.parseBoolean(value); } private static ProjectionType parseType(String key, String xmp, ProjectionType defaultValue) { String value = parseString(key, xmp); - return value == null ? defaultValue : ProjectionType.equirectangular; + if (value == null) { + return defaultValue; + } + return ProjectionType.equirectangular; } private static Date parseDate(String key, String xmp, Date defaultValue) { String value = parseString(key, xmp); try { - return value == null ? defaultValue : dateFormat.parse(value); + if (value == null) { + return defaultValue; + } + return dateFormat.parse(value); } catch (ParseException e) { return defaultValue; } diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml new file mode 100644 index 0000000..a6b3dae --- /dev/null +++ b/app/src/main/res/values-v21/styles.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From 09241253c8f66fa9a91d2c45bb82b9777eb6b1ae Mon Sep 17 00:00:00 2001 From: vanitasvitae Date: Fri, 15 Sep 2017 00:56:08 +0200 Subject: [PATCH 2/6] Make system bars completely transparent --- .../java/de/trac/spherical/MainActivity.java | 20 +++++++---- app/src/main/res/layout/activity_main.xml | 34 +++++++------------ app/src/main/res/values-v21/styles.xml | 16 ++++++++- 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/de/trac/spherical/MainActivity.java b/app/src/main/java/de/trac/spherical/MainActivity.java index bc7d659..aa16846 100644 --- a/app/src/main/java/de/trac/spherical/MainActivity.java +++ b/app/src/main/java/de/trac/spherical/MainActivity.java @@ -3,6 +3,7 @@ package de.trac.spherical; import android.content.Intent; import android.graphics.BitmapFactory; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.support.design.widget.AppBarLayout; import android.support.design.widget.FloatingActionButton; @@ -15,7 +16,10 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; +import android.view.Window; +import android.view.WindowManager; import android.widget.LinearLayout; +import android.widget.RelativeLayout; import android.widget.Toast; import java.io.FileNotFoundException; @@ -38,7 +42,6 @@ public class MainActivity extends AppCompatActivity { private Renderer renderer; private FloatingActionButton fab; private Toolbar toolbar; - private AppBarLayout appBarLayout; @Override protected void onCreate(Bundle savedInstanceState) { @@ -49,10 +52,9 @@ public class MainActivity extends AppCompatActivity { toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); getSupportActionBar().setDisplayShowTitleEnabled(false); - appBarLayout = (AppBarLayout) findViewById(R.id.lay_toolbar); - AppBarLayout.LayoutParams lp = (AppBarLayout.LayoutParams) toolbar.getLayoutParams(); + RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) toolbar.getLayoutParams(); lp.topMargin += getStatusBarHeight(); - appBarLayout.bringToFront(); + toolbar.bringToFront(); fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override @@ -62,6 +64,11 @@ public class MainActivity extends AppCompatActivity { } }); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + Window w = getWindow(); + w.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + } + // Initialize renderer and setup surface view. LinearLayout container = (LinearLayout) findViewById(R.id.container); surfaceView = new SphereSurfaceView(this); @@ -102,10 +109,10 @@ public class MainActivity extends AppCompatActivity { private void displayUI(boolean display) { if (display) { fab.show(); - appBarLayout.setExpanded(true, true); + toolbar.setVisibility(View.VISIBLE); } else { fab.setVisibility(View.INVISIBLE); - appBarLayout.setExpanded(false, true); + toolbar.setVisibility(View.GONE); } } @@ -223,6 +230,7 @@ public class MainActivity extends AppCompatActivity { */ private void displayFlatImage(InputStream inputStream) { Log.d(TAG, "Display Flat Image!"); + displayPhotoSphere(inputStream, new PhotoSphereMetadata()); } public int getStatusBarHeight() { diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index bacd066..ea61a5c 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,5 +1,5 @@ - - - - - - + android:layout_alignParentTop="true" + app:layout_scrollFlags="scroll|enterAlways|snap" + app:theme="@style/AppTheme.ActionBar" + app:popupTheme="@style/ThemeOverlay.AppCompat" /> - + diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml index a6b3dae..aaef456 100644 --- a/app/src/main/res/values-v21/styles.xml +++ b/app/src/main/res/values-v21/styles.xml @@ -1,2 +1,16 @@ - \ No newline at end of file + + + + \ No newline at end of file From 7ae568c3b0828b8feaee9d2f7a4b0a8b243543c6 Mon Sep 17 00:00:00 2001 From: vanitasvitae Date: Fri, 15 Sep 2017 01:17:35 +0200 Subject: [PATCH 3/6] Ask for permission to access external storage --- app/build.gradle | 2 +- .../java/de/trac/spherical/MainActivity.java | 46 +++++++++++++++++-- app/src/main/res/values/strings.xml | 1 + 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 119e145..767da27 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,7 +5,7 @@ android { buildToolsVersion "25.0.3" defaultConfig { applicationId "de.trac.spherical" - minSdkVersion 15 + minSdkVersion 16 targetSdkVersion 25 versionCode 1 versionName "1.0" diff --git a/app/src/main/java/de/trac/spherical/MainActivity.java b/app/src/main/java/de/trac/spherical/MainActivity.java index aa16846..12e5425 100644 --- a/app/src/main/java/de/trac/spherical/MainActivity.java +++ b/app/src/main/java/de/trac/spherical/MainActivity.java @@ -1,12 +1,15 @@ package de.trac.spherical; +import android.Manifest; import android.content.Intent; +import android.content.pm.PackageManager; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.support.design.widget.AppBarLayout; import android.support.design.widget.FloatingActionButton; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; @@ -38,11 +41,15 @@ public class MainActivity extends AppCompatActivity { public static final String MIME_PHOTO_SPHERE = "application/vnd.google.panorama360+jpg"; public static final String MIME_IMAGE = "image/*"; + private static final int PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 387; + private SphereSurfaceView surfaceView; private Renderer renderer; private FloatingActionButton fab; private Toolbar toolbar; + private Intent cachedIntent; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -92,11 +99,14 @@ public class MainActivity extends AppCompatActivity { } }); - Intent intent = getIntent(); + handleIntent(getIntent()); + } + + private void handleIntent(Intent intent) { switch (intent.getAction()) { //Image was sent into the app case Intent.ACTION_SEND: - handleSentImageIntent(intent); + checkPermissionAndHandleSentImage(intent); break; //App was launched via launcher icon @@ -106,6 +116,36 @@ public class MainActivity extends AppCompatActivity { } } + private void checkPermissionAndHandleSentImage(Intent intent) { + int status = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE); + if (status == PackageManager.PERMISSION_GRANTED) { + handleSentImageIntent(intent); + } + + // Cache intent and request permission + this.cachedIntent = intent; + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, + PERMISSION_REQUEST_READ_EXTERNAL_STORAGE); + + } + + @Override + public void onRequestPermissionsResult(int requestCode, + String permissions[], int[] grantResults) { + switch (requestCode) { + case PERMISSION_REQUEST_READ_EXTERNAL_STORAGE: { + // If request is cancelled, the result arrays are empty. + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + handleSentImageIntent(cachedIntent); + } else { + Toast.makeText(this, R.string.missing_permission, Toast.LENGTH_LONG).show(); + } + return; + } + } + } + private void displayUI(boolean display) { if (display) { fab.show(); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fefa961..a384a13 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -6,4 +6,5 @@ WOW! SUCH 3D!!! Show as Sphere Not yet implemented! + Cannot display photo: Missing permissions to access external storage. From a0d7071861b1c3770f6fafe95d37e52d6c6e40b9 Mon Sep 17 00:00:00 2001 From: vanitasvitae Date: Fri, 15 Sep 2017 01:30:06 +0200 Subject: [PATCH 4/6] Disable backup --- app/src/main/AndroidManifest.xml | 2 +- app/src/main/res/values-de/strings.xml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/values-de/strings.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cf3a456..c15743d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,7 +5,7 @@ + \ No newline at end of file From bd921bfc1b020c13c70df6b40f3c9d053e8f08d9 Mon Sep 17 00:00:00 2001 From: vanitasvitae Date: Fri, 15 Sep 2017 01:30:36 +0200 Subject: [PATCH 5/6] Fix warnings, add german translation --- .../java/de/trac/spherical/MainActivity.java | 19 +++---- .../de/trac/spherical/rendering/Renderer.java | 51 ++++++++++++++++++- app/src/main/res/values-de/strings.xml | 9 +++- app/src/main/res/values/strings.xml | 13 +++-- 4 files changed, 73 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/de/trac/spherical/MainActivity.java b/app/src/main/java/de/trac/spherical/MainActivity.java index 12e5425..d103db0 100644 --- a/app/src/main/java/de/trac/spherical/MainActivity.java +++ b/app/src/main/java/de/trac/spherical/MainActivity.java @@ -112,7 +112,7 @@ public class MainActivity extends AppCompatActivity { //App was launched via launcher icon //TODO: Remove later together with launcher intent filter default: - Toast.makeText(this, R.string.prompt_share_image, Toast.LENGTH_LONG).show(); + Toast.makeText(this, R.string.toast_prompt_share_image, Toast.LENGTH_LONG).show(); } } @@ -139,9 +139,8 @@ public class MainActivity extends AppCompatActivity { && grantResults[0] == PackageManager.PERMISSION_GRANTED) { handleSentImageIntent(cachedIntent); } else { - Toast.makeText(this, R.string.missing_permission, Toast.LENGTH_LONG).show(); + Toast.makeText(this, R.string.toast_missing_permission, Toast.LENGTH_LONG).show(); } - return; } } } @@ -173,7 +172,7 @@ public class MainActivity extends AppCompatActivity { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_force_sphere: - Toast.makeText(this, R.string.not_yet_implemented, Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.toast_not_yet_implemented, Toast.LENGTH_SHORT).show(); return true; } @@ -191,7 +190,7 @@ public class MainActivity extends AppCompatActivity { Uri imageUri = intent.getParcelableExtra(Intent.EXTRA_STREAM); if (imageUri == null) { - Toast.makeText(this, R.string.file_not_found, Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.toast_file_not_found, Toast.LENGTH_SHORT).show(); return; } @@ -227,9 +226,11 @@ public class MainActivity extends AppCompatActivity { } } catch (FileNotFoundException e) { - e.printStackTrace(); + Log.e(TAG, "File not found.", e); + Toast.makeText(this, R.string.toast_file_not_found, Toast.LENGTH_SHORT).show(); } catch (IOException e) { - e.printStackTrace(); + Log.e(TAG, "IOException: ", e); + Toast.makeText(this, R.string.toast_io_error, Toast.LENGTH_SHORT).show(); } } @@ -252,10 +253,10 @@ public class MainActivity extends AppCompatActivity { } catch (FileNotFoundException e) { Log.e(TAG, "File not found.", e); - Toast.makeText(this, R.string.file_not_found, Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.toast_file_not_found, Toast.LENGTH_SHORT).show(); } catch (IOException e) { Log.e(TAG, "IOException: ", e); - Toast.makeText(this, R.string.ioerror, Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.toast_io_error, Toast.LENGTH_SHORT).show(); } } diff --git a/app/src/main/java/de/trac/spherical/rendering/Renderer.java b/app/src/main/java/de/trac/spherical/rendering/Renderer.java index 7764237..23eaccb 100644 --- a/app/src/main/java/de/trac/spherical/rendering/Renderer.java +++ b/app/src/main/java/de/trac/spherical/rendering/Renderer.java @@ -10,8 +10,55 @@ import android.util.Log; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; -import static android.opengl.GLES20.*; -import static android.opengl.GLUtils.getEGLErrorString; +import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT; +import static android.opengl.GLES20.GL_COMPILE_STATUS; +import static android.opengl.GLES20.GL_CULL_FACE; +import static android.opengl.GLES20.GL_CW; +import static android.opengl.GLES20.GL_DEPTH_BUFFER_BIT; +import static android.opengl.GLES20.GL_DEPTH_TEST; +import static android.opengl.GLES20.GL_FLOAT; +import static android.opengl.GLES20.GL_FRAGMENT_SHADER; +import static android.opengl.GLES20.GL_LINEAR; +import static android.opengl.GLES20.GL_LINK_STATUS; +import static android.opengl.GLES20.GL_NEAREST; +import static android.opengl.GLES20.GL_TEXTURE0; +import static android.opengl.GLES20.GL_TEXTURE_2D; +import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER; +import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER; +import static android.opengl.GLES20.GL_TRIANGLES; +import static android.opengl.GLES20.GL_TRUE; +import static android.opengl.GLES20.GL_UNSIGNED_SHORT; +import static android.opengl.GLES20.GL_VERTEX_SHADER; +import static android.opengl.GLES20.glActiveTexture; +import static android.opengl.GLES20.glAttachShader; +import static android.opengl.GLES20.glBindTexture; +import static android.opengl.GLES20.glClear; +import static android.opengl.GLES20.glClearColor; +import static android.opengl.GLES20.glCompileShader; +import static android.opengl.GLES20.glCreateProgram; +import static android.opengl.GLES20.glCreateShader; +import static android.opengl.GLES20.glDeleteProgram; +import static android.opengl.GLES20.glDeleteShader; +import static android.opengl.GLES20.glDisableVertexAttribArray; +import static android.opengl.GLES20.glDrawElements; +import static android.opengl.GLES20.glEnable; +import static android.opengl.GLES20.glEnableVertexAttribArray; +import static android.opengl.GLES20.glFrontFace; +import static android.opengl.GLES20.glGenTextures; +import static android.opengl.GLES20.glGetAttribLocation; +import static android.opengl.GLES20.glGetProgramInfoLog; +import static android.opengl.GLES20.glGetProgramiv; +import static android.opengl.GLES20.glGetShaderInfoLog; +import static android.opengl.GLES20.glGetShaderiv; +import static android.opengl.GLES20.glGetUniformLocation; +import static android.opengl.GLES20.glLinkProgram; +import static android.opengl.GLES20.glShaderSource; +import static android.opengl.GLES20.glTexParameteri; +import static android.opengl.GLES20.glUniform1i; +import static android.opengl.GLES20.glUniformMatrix4fv; +import static android.opengl.GLES20.glUseProgram; +import static android.opengl.GLES20.glVertexAttribPointer; +import static android.opengl.GLES20.glViewport; public class Renderer implements GLSurfaceView.Renderer { diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index a6b3dae..0755aec 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1,2 +1,9 @@ - \ No newline at end of file + + Erzwinge Kugelansicht + Datei nicht gefunden. + Ein Fehler ist aufgetreten: IO-Error. + Foto kann nicht angezeigt werden: Fehlende Berechtigung für externen Speicher. + Noch nicht implementiert! + Teile ein Bild mit der App! + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a384a13..3f60415 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,10 +1,9 @@ - Spherical - Share an image with the app! - File not found. - An Error has occurred: IOError. - WOW! SUCH 3D!!! + Spherical + Share an image with the app! + File not found. + An Error has occurred: IO-Error. Show as Sphere - Not yet implemented! - Cannot display photo: Missing permissions to access external storage. + Not yet implemented! + Cannot display photo: Missing permissions to access external storage. From 0fe9bb7ce7acf93c69c817fc4d21868f27176362 Mon Sep 17 00:00:00 2001 From: vanitasvitae Date: Fri, 15 Sep 2017 01:40:27 +0200 Subject: [PATCH 6/6] Load images in AsyncTask. Fixes #10. --- .../de/trac/spherical/HandleImageTask.java | 23 +++++++++++++++++++ .../java/de/trac/spherical/MainActivity.java | 6 ++--- 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/de/trac/spherical/HandleImageTask.java diff --git a/app/src/main/java/de/trac/spherical/HandleImageTask.java b/app/src/main/java/de/trac/spherical/HandleImageTask.java new file mode 100644 index 0000000..15992ab --- /dev/null +++ b/app/src/main/java/de/trac/spherical/HandleImageTask.java @@ -0,0 +1,23 @@ +package de.trac.spherical; + +import android.content.Intent; +import android.os.AsyncTask; + +/** + * Created by vanitas on 15.09.17. + */ + +public class HandleImageTask extends AsyncTask { + + private MainActivity mainActivity; + + public HandleImageTask(MainActivity mainActivity) { + this.mainActivity = mainActivity; + } + + @Override + protected Void doInBackground(Intent... params) { + mainActivity.handleSentImageIntent(params[0]); + return null; + } +} diff --git a/app/src/main/java/de/trac/spherical/MainActivity.java b/app/src/main/java/de/trac/spherical/MainActivity.java index d103db0..a30c53e 100644 --- a/app/src/main/java/de/trac/spherical/MainActivity.java +++ b/app/src/main/java/de/trac/spherical/MainActivity.java @@ -119,7 +119,7 @@ public class MainActivity extends AppCompatActivity { private void checkPermissionAndHandleSentImage(Intent intent) { int status = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE); if (status == PackageManager.PERMISSION_GRANTED) { - handleSentImageIntent(intent); + new HandleImageTask(this).doInBackground(intent); } // Cache intent and request permission @@ -137,7 +137,7 @@ public class MainActivity extends AppCompatActivity { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - handleSentImageIntent(cachedIntent); + new HandleImageTask(this).doInBackground(cachedIntent); } else { Toast.makeText(this, R.string.toast_missing_permission, Toast.LENGTH_LONG).show(); } @@ -184,7 +184,7 @@ public class MainActivity extends AppCompatActivity { * displayed, while images with MIME type image/* are being manually tested using {@link PhotoSphereParser}. * @param intent incoming intent. */ - private void handleSentImageIntent(Intent intent) { + void handleSentImageIntent(Intent intent) { String type = intent.getType(); if (type != null) {