[Libreoffice-commits] core.git: android/source

Ximeng Zu uznomis at yahoo.com
Tue Jul 11 08:52:47 UTC 2017


 android/source/AndroidManifest.xml                                   |    7 
 android/source/res/layout/presentation_mode.xml                      |   45 ++
 android/source/res/menu/main.xml                                     |    5 
 android/source/res/values/strings.xml                                |    4 
 android/source/src/java/org/libreoffice/LOKitTileProvider.java       |   52 +-
 android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java |   41 ++
 android/source/src/java/org/libreoffice/PresentationActivity.java    |  188 ++++++++++
 android/source/src/java/org/libreoffice/ToolbarController.java       |    3 
 8 files changed, 329 insertions(+), 16 deletions(-)

New commits:
commit 6b873439042960bfc72a5e341c5ed61eeb40f53e
Author: Ximeng Zu <uznomis at yahoo.com>
Date:   Wed May 24 17:02:17 2017 -0500

    Presentation Mode
    
    Adding fullscreen presentation mode.
    
    Change-Id: Id07416ce204d1d7dd917fbd33a4d9f5072ac1703
    Reviewed-on: https://gerrit.libreoffice.org/38006
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>
    Tested-by: Tomaž Vajngerl <quikee at gmail.com>

diff --git a/android/source/AndroidManifest.xml b/android/source/AndroidManifest.xml
index 0b384a3becc2..a9c3a3a1609d 100644
--- a/android/source/AndroidManifest.xml
+++ b/android/source/AndroidManifest.xml
@@ -125,6 +125,13 @@
             android:windowSoftInputMode="stateHidden">
         </activity>
 
+        <activity android:name=".PresentationActivity"
+            android:screenOrientation="landscape" >
+            <meta-data
+                android:name="android.support.PARENT_ACTIVITY"
+                android:value=".LibreOfficeMainActivity" />
+        </activity>
+
     </application>
 
 </manifest>
diff --git a/android/source/res/layout/presentation_mode.xml b/android/source/res/layout/presentation_mode.xml
new file mode 100644
index 000000000000..ec1845ab68ab
--- /dev/null
+++ b/android/source/res/layout/presentation_mode.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent" android:layout_height="match_parent">
+
+    <WebView
+        android:id="@+id/presentation_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+    <RelativeLayout
+        android:id="@+id/presentation_gesture_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:animateLayoutChanges="true">
+
+        <ImageButton
+            android:id="@+id/slide_show_nav_prev"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentEnd="true"
+            android:layout_alignParentRight="true"
+            android:layout_alignParentTop="true"
+            android:src="@drawable/ic_search_direction_up" />
+
+        <ImageButton
+            android:id="@+id/slide_show_nav_next"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentEnd="true"
+            android:layout_alignParentRight="true"
+            android:src="@drawable/ic_search_direction_down" />
+
+        <Button
+            android:id="@+id/slide_show_nav_back"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentStart="true"
+            android:layout_alignParentTop="true"
+            android:text="@string/slideshow_action_back" />
+
+    </RelativeLayout>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/android/source/res/menu/main.xml b/android/source/res/menu/main.xml
index 3ec0dadc5b63..0b34d8b5ffac 100644
--- a/android/source/res/menu/main.xml
+++ b/android/source/res/menu/main.xml
@@ -42,6 +42,11 @@
             android:orderInCategory="100" />
     </group>
 
+    <item android:id="@+id/action_presentation"
+        android:title="@string/action_presentation"
+        android:orderInCategory="100"
+        android:enabled="false" />
+
     <item android:id="@+id/action_parts"
           android:title="@string/action_parts"
           android:orderInCategory="100" />
diff --git a/android/source/res/values/strings.xml b/android/source/res/values/strings.xml
index 4495ca584927..ad4d2699684a 100644
--- a/android/source/res/values/strings.xml
+++ b/android/source/res/values/strings.xml
@@ -130,5 +130,9 @@
     <!-- Create New Document Dialog Strings -->
     <string name="create_new_document_title">Enter file name</string>
     <string name="action_create">CREATE</string>
+    <string name="action_presentation">Slide show</string>
+    <string name="alert_copy_svg_slide_show_to_clipboard">Your Android device doesn\'t support in-app svg slideshow. We copied the slideshow link to clipboard. Please press home button, open a modern web browser, paste in the address bar, and go.</string>
+    <string name="alert_copy_svg_slide_show_to_clipboard_dismiss">OK</string>
+    <string name="slideshow_action_back">Back</string>
 
 </resources>
diff --git a/android/source/src/java/org/libreoffice/LOKitTileProvider.java b/android/source/src/java/org/libreoffice/LOKitTileProvider.java
index e17893985a75..6fb8a9b80671 100644
--- a/android/source/src/java/org/libreoffice/LOKitTileProvider.java
+++ b/android/source/src/java/org/libreoffice/LOKitTileProvider.java
@@ -101,6 +101,10 @@ class LOKitTileProvider implements TileProvider {
         Log.i(LOGTAG, "Document parts: " + parts);
         mContext.getDocumentPartView().clear();
 
+        if (mDocument.getDocumentType() == Document.DOCTYPE_PRESENTATION) {
+            mContext.getToolbarController().disableMenuItem(R.id.action_presentation, false);
+        }
+
         // Writer documents always have one part, so hide the navigation drawer.
         if (mDocument.getDocumentType() != Document.DOCTYPE_TEXT) {
             for (int i = 0; i < parts; i++) {
@@ -134,26 +138,44 @@ class LOKitTileProvider implements TileProvider {
 
     @Override
     public void saveDocumentAs(String filePath, String format) {
-        String newFilePath = "file://" + filePath;
+        final String newFilePath = "file://" + filePath;
         Log.d("saveFilePathURL", newFilePath);
+        LOKitShell.showProgressSpinner(mContext);
         mDocument.saveAs(newFilePath, format, "");
         if (!mOffice.getError().isEmpty()){
             Log.e("Save Error", mOffice.getError());
-            LOKitShell.getMainHandler().post(new Runnable() {
-                @Override
-                public void run() {
-                    // There was some error
-                    mContext.showSaveStatusMessage(true);
-                }
-            });
-        }
-        LOKitShell.getMainHandler().post(new Runnable() {
-            @Override
-            public void run() {
-                // There was no error
-                mContext.showSaveStatusMessage(false);
+            if (format.equals("svg")) {
+                // error in creating temp slideshow svg file
+                Log.d(LOGTAG, "Error in creating temp slideshow svg file");
+            } else {
+                LOKitShell.getMainHandler().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        // There was some error
+                        mContext.showSaveStatusMessage(true);
+                    }
+                });
             }
-        });
+        } else {
+            if (format.equals("svg")) {
+                // successfully created temp slideshow svg file
+                LOKitShell.getMainHandler().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mContext.startPresentation(newFilePath);
+                    }
+                });
+            } else {
+                LOKitShell.getMainHandler().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        // There was no error
+                        mContext.showSaveStatusMessage(false);
+                    }
+                });
+            }
+        }
+        LOKitShell.hideProgressSpinner(mContext);
     }
 
     private void setupDocumentFonts() {
diff --git a/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java b/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java
index b4f8dc77f60b..8aeb1f5ff816 100755
--- a/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java
+++ b/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java
@@ -2,6 +2,8 @@ package org.libreoffice;
 
 import android.app.Activity;
 import android.app.AlertDialog;
+import android.content.ClipData;
+import android.content.ClipboardManager;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -10,12 +12,14 @@ import android.content.SharedPreferences;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.AssetManager;
 import android.graphics.RectF;
+import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.preference.PreferenceManager;
-import android.support.design.widget.Snackbar;
 import android.support.design.widget.BottomSheetBehavior;
+import android.support.design.widget.Snackbar;
 import android.support.v4.widget.DrawerLayout;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
@@ -79,6 +83,7 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin
     private File mInputFile;
     private DocumentOverlay mDocumentOverlay;
     private File mTempFile = null;
+    private File mTempSlideShowFile = null;
     private String newDocumentType = null;
 
     BottomSheetBehavior bottomToolbarSheetBehavior;
@@ -407,6 +412,10 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin
                 // noinspection ResultOfMethodCallIgnored
                 mTempFile.delete();
             }
+            if (mTempSlideShowFile.exists()) {
+                // noinspection ResultOfMethodCallIgnored
+                mTempSlideShowFile.delete();
+            }
         }
     }
     @Override
@@ -749,6 +758,36 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin
             Snackbar.make(mDrawerLayout, getString(R.string.create_new_file_success) + mInputFile.getName(), Snackbar.LENGTH_LONG).show();
         else
             Snackbar.make(mDrawerLayout, getString(R.string.create_new_file_error) + mInputFile.getName(), Snackbar.LENGTH_LONG).show();    }
+
+    public void preparePresentation() {
+        if (getExternalCacheDir() != null) {
+            String tempPath = getExternalCacheDir().getPath() + "/" + mInputFile.getName() + ".svg";
+            mTempSlideShowFile = new File(tempPath);
+            if (mTempSlideShowFile.exists() && !isDocumentChanged) {
+                startPresentation("file://" + tempPath);
+            } else {
+                LOKitShell.sendSaveAsEvent(tempPath, "svg");
+            }
+        }
+    }
+
+    public void startPresentation(String tempPath) {
+        // pre-KitKat android doesn't have chrome-based WebView, which is needed to show svg slideshow
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+            Intent intent = new Intent(this, PresentationActivity.class);
+            intent.setData(Uri.parse(tempPath));
+            startActivity(intent);
+        } else {
+            // copy the svg file path to clipboard for the user to paste in a browser
+            ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
+            ClipData clip = ClipData.newPlainText("temp svg file path", tempPath);
+            clipboard.setPrimaryClip(clip);
+
+            AlertDialog.Builder builder = new AlertDialog.Builder(this);
+            builder.setMessage(R.string.alert_copy_svg_slide_show_to_clipboard)
+                    .setPositiveButton(R.string.alert_copy_svg_slide_show_to_clipboard_dismiss, null).show();
+        }
+    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/android/source/src/java/org/libreoffice/PresentationActivity.java b/android/source/src/java/org/libreoffice/PresentationActivity.java
new file mode 100644
index 000000000000..1eea5e3836fb
--- /dev/null
+++ b/android/source/src/java/org/libreoffice/PresentationActivity.java
@@ -0,0 +1,188 @@
+package org.libreoffice;
+
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.view.GestureDetectorCompat;
+import android.support.v7.app.AppCompatActivity;
+import android.view.GestureDetector;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.webkit.WebView;
+import android.widget.Button;
+import android.widget.ImageButton;
+
+public class PresentationActivity extends AppCompatActivity {
+
+    private static final String LOGTAG = PresentationActivity.class.getSimpleName();
+    WebView mWebView;
+    View mGestureView;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // First we hide the status bar
+        if (Build.VERSION.SDK_INT < 16) {
+            // If the Android version is lower than Jellybean, use this call to hide
+            // the status bar.
+            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
+        } else {
+            // If higher than Jellybean
+            View decorView = getWindow().getDecorView();
+            // Hide the status bar.
+            int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
+            decorView.setSystemUiVisibility(uiOptions);
+        }
+
+        setContentView(R.layout.presentation_mode);
+
+        // get intent and url
+        Intent intent = getIntent();
+        String filePath = intent.getDataString();
+
+        // set up WebView
+        mWebView = (WebView) findViewById(R.id.presentation_view);
+        mWebView.getSettings().setJavaScriptEnabled(true);
+        mWebView.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                return true;
+            }
+        });
+
+        // set up buttons within presentation_gesture_view
+        ImageButton prevButton = (ImageButton) findViewById(R.id.slide_show_nav_prev);
+        ImageButton nextButton = (ImageButton) findViewById(R.id.slide_show_nav_next);
+        Button backButton = (Button) findViewById(R.id.slide_show_nav_back);
+
+        prevButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                pageLeft();
+            }
+        });
+        nextButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                pageRight();
+            }
+        });
+        backButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                onBackPressed();
+            }
+        });
+
+        // set up presentation_gesture_view
+        mGestureView = findViewById(R.id.presentation_gesture_view);
+        final GestureDetectorCompat gestureDetector =
+                new GestureDetectorCompat(this, new presentationGestureViewListener());
+        mGestureView.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                return gestureDetector.onTouchEvent(event);
+            }
+        });
+
+        // load url
+        mWebView.loadUrl(filePath);
+    }
+
+    private class presentationGestureViewListener extends GestureDetector.SimpleOnGestureListener {
+        private static final int SWIPE_VELOCITY_THRESHOLD = 100;
+        private static final int SCROLL_THRESHOLD = 10; // if scrollCounter is larger than this, a page switch is triggered
+        private int scrollCounter = 0; // a counter for measuring scrolling distance
+
+        @Override
+        public boolean onDown(MotionEvent e) {
+            return true;
+        }
+
+        @Override
+        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+            boolean result = false;
+            try {
+                float diffY = e2.getY() - e1.getY();
+                float diffX = e2.getX() - e1.getX();
+                if (Math.abs(diffX) > Math.abs(diffY)) {
+                    if (Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
+                        if (diffX > 0) {
+                            pageRight();
+                        } else {
+                            pageLeft();
+                        }
+                        result = true;
+                    }
+                }
+            } catch (Exception exception) {
+                exception.printStackTrace();
+            }
+            return result;
+        }
+
+        @Override
+        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+            boolean result = false;
+            try {
+                float diffY = e2.getY() - e1.getY();
+                float diffX = e2.getX() - e1.getX();
+                if (Math.abs(diffX) < Math.abs(diffY)) {
+                    if (distanceY > 0) {
+                        scrollCounter++;
+                        if (scrollCounter >= SCROLL_THRESHOLD) {
+                            pageRight();
+                            scrollCounter = 0;
+                        }
+                    } else {
+                        scrollCounter--;
+                        if (scrollCounter <= -SCROLL_THRESHOLD) {
+                            pageLeft();
+                            scrollCounter = 0;
+                        }
+                    }
+                    result = true;
+                }
+            } catch (Exception exception) {
+                exception.printStackTrace();
+            }
+            return result;
+        }
+
+        @Override
+        public boolean onSingleTapUp(MotionEvent e) {
+            if (e.getX() < mGestureView.getWidth()/3) {
+                pageLeft();
+            } else if (e.getX() < mGestureView.getWidth()*2/3) {
+                hideControlButtons();
+            } else {
+                pageRight();
+            }
+            return true;
+        }
+    }
+
+    private void hideControlButtons() {
+        View[] views= {findViewById(R.id.slide_show_nav_prev),findViewById(R.id.slide_show_nav_next),findViewById(R.id.slide_show_nav_back)} ;
+        for (View view : views) {
+            if (view.getVisibility() == View.GONE) {
+                view.setVisibility(View.VISIBLE);
+            } else if (view.getVisibility() == View.VISIBLE) {
+                view.setVisibility(View.GONE);
+            }
+        }
+    }
+
+    private void pageLeft() {
+        mWebView.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT));
+    }
+
+    private void pageRight() {
+        mWebView.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT));
+    }
+}
\ No newline at end of file
diff --git a/android/source/src/java/org/libreoffice/ToolbarController.java b/android/source/src/java/org/libreoffice/ToolbarController.java
index d7f1ac18c95e..9ef994d271a9 100644
--- a/android/source/src/java/org/libreoffice/ToolbarController.java
+++ b/android/source/src/java/org/libreoffice/ToolbarController.java
@@ -132,6 +132,9 @@ public class ToolbarController implements Toolbar.OnMenuItemClickListener {
             case R.id.action_redo:
                 LOKitShell.sendEvent(new LOEvent(LOEvent.UNO_COMMAND, ".uno:Redo"));
                 return true;
+            case R.id.action_presentation:
+                mContext.preparePresentation();
+                return true;
         }
         return false;
     }


More information about the Libreoffice-commits mailing list