diff options
author | Yuichi Araki <yaraki@google.com> | 2019-01-20 20:11:53 -0800 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2019-01-20 20:11:53 -0800 |
commit | 278c1d5def726087a7431214a9ed15c6918f3a0f (patch) | |
tree | 4a4c7ff6c9811cbf4121ff8b7ceb1eaaec2801db /ui | |
parent | 47bb8f445917f90ad1d723e02ae567ea41c2e099 (diff) | |
parent | 9009018ee628628c02e1c266e601e52132782d50 (diff) | |
download | android-278c1d5def726087a7431214a9ed15c6918f3a0f.tar.gz |
PdfRendererBasic: Modernize the sample am: c87ea8c2ca
am: 9009018ee6
Change-Id: If04f160ef85682680b20968829b1a0ad12520107
Diffstat (limited to 'ui')
28 files changed, 844 insertions, 855 deletions
diff --git a/ui/graphics/PdfRendererBasic/Application/.gitignore b/ui/graphics/PdfRendererBasic/Application/.gitignore deleted file mode 100644 index 6eb878d4..00000000 --- a/ui/graphics/PdfRendererBasic/Application/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2013 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -src/template/ -src/common/ -build.gradle diff --git a/ui/graphics/PdfRendererBasic/Application/build.gradle b/ui/graphics/PdfRendererBasic/Application/build.gradle new file mode 100644 index 00000000..fa47dfe9 --- /dev/null +++ b/ui/graphics/PdfRendererBasic/Application/build.gradle @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 28 + + defaultConfig { + applicationId 'com.example.android.pdfrendererbasic' + minSdkVersion 21 + targetSdkVersion 28 + versionCode 1 + versionName '1.0' + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + testOptions { + unitTests { + returnDefaultValues = true + includeAndroidResources = true + } + } +} + +dependencies { + implementation 'androidx.appcompat:appcompat:1.0.2' + + def lifecycle_version = '2.0.0' + implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" + androidTestImplementation "androidx.arch.core:core-testing:$lifecycle_version" + + testImplementation 'com.google.truth:truth:0.42' + testImplementation 'androidx.test:core:1.1.0' + testImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.ext:truth:1.1.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' +} diff --git a/ui/graphics/PdfRendererBasic/Application/src/androidTest/java/com/example/android/pdfrendererbasic/PdfRendererBasicTest.java b/ui/graphics/PdfRendererBasic/Application/src/androidTest/java/com/example/android/pdfrendererbasic/PdfRendererBasicTest.java new file mode 100644 index 00000000..105034b6 --- /dev/null +++ b/ui/graphics/PdfRendererBasic/Application/src/androidTest/java/com/example/android/pdfrendererbasic/PdfRendererBasicTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.pdfrendererbasic; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import androidx.fragment.app.Fragment; +import androidx.test.core.app.ActivityScenario; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.isEnabled; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; +import static com.google.common.truth.Truth.assertThat; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.core.AllOf.allOf; + +@RunWith(AndroidJUnit4.class) +@LargeTest +public class PdfRendererBasicTest { + + @Test + public void integration() { + final ActivityScenario<MainActivity> scenario = ActivityScenario.launch(MainActivity.class); + scenario.onActivity((activity) -> { + final Fragment fragment = activity.getSupportFragmentManager() + .findFragmentById(R.id.container); + assertThat(fragment).isInstanceOf(PdfRendererBasicFragment.class); + }); + onView(withId(R.id.image)).check(matches(isDisplayed())); + onView(withId(R.id.previous)).check(matches(allOf(isDisplayed(), not(isEnabled())))); + onView(withId(R.id.next)).check(matches(allOf(isDisplayed(), isEnabled()))); + onView(withText("PdfRendererBasic (1/10)")).check(matches(isDisplayed())); + onView(withId(R.id.next)).perform(click()); + onView(withText("PdfRendererBasic (2/10)")).check(matches(isDisplayed())); + onView(withId(R.id.previous)).check(matches(allOf(isDisplayed(), isEnabled()))); + onView(withId(R.id.next)).check(matches(allOf(isDisplayed(), isEnabled()))); + for (int i = 0; i < 8; i++) { + onView(withId(R.id.next)).perform(click()); + } + onView(withText("PdfRendererBasic (10/10)")).check(matches(isDisplayed())); + onView(withId(R.id.previous)).check(matches(allOf(isDisplayed(), isEnabled()))); + onView(withId(R.id.next)).check(matches(allOf(isDisplayed(), not(isEnabled())))); + } + +} diff --git a/ui/graphics/PdfRendererBasic/Application/src/androidTest/java/com/example/android/pdfrendererbasic/PdfRendererBasicViewModelTest.java b/ui/graphics/PdfRendererBasic/Application/src/androidTest/java/com/example/android/pdfrendererbasic/PdfRendererBasicViewModelTest.java new file mode 100644 index 00000000..bd1d5d86 --- /dev/null +++ b/ui/graphics/PdfRendererBasic/Application/src/androidTest/java/com/example/android/pdfrendererbasic/PdfRendererBasicViewModelTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.pdfrendererbasic; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import androidx.arch.core.executor.testing.InstantTaskExecutorRule; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.filters.MediumTest; +import androidx.test.runner.AndroidJUnit4; + +import static com.google.common.truth.Truth.assertThat; + +@RunWith(AndroidJUnit4.class) +@MediumTest +public class PdfRendererBasicViewModelTest { + + @Rule + public final InstantTaskExecutorRule rule = new InstantTaskExecutorRule(); + + private PdfRendererBasicViewModel mViewModel = new PdfRendererBasicViewModel( + ApplicationProvider.getApplicationContext(), true); + + @Test + public void allPages() { + assertThat(mViewModel).isNotNull(); + final PdfRendererBasicViewModel.PageInfo firstInfo = mViewModel.getPageInfo().getValue(); + assertThat(firstInfo).isNotNull(); + assertThat(firstInfo.index).isEqualTo(0); + assertThat(firstInfo.count).isEqualTo(10); + assertThat(mViewModel.getPreviousEnabled().getValue()).isFalse(); + assertThat(mViewModel.getNextEnabled().getValue()).isTrue(); + assertThat(mViewModel.getPageBitmap().getValue()).isNotNull(); + for (int i = 0; i < 9; i++) { + mViewModel.showNext(); + } + final PdfRendererBasicViewModel.PageInfo lastInfo = mViewModel.getPageInfo().getValue(); + assertThat(lastInfo).isNotNull(); + assertThat(lastInfo.index).isEqualTo(9); + assertThat(lastInfo.count).isEqualTo(10); + assertThat(mViewModel.getPreviousEnabled().getValue()).isTrue(); + assertThat(mViewModel.getNextEnabled().getValue()).isFalse(); + assertThat(mViewModel.getPageBitmap().getValue()).isNotNull(); + } + +} diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/AndroidManifest.xml b/ui/graphics/PdfRendererBasic/Application/src/main/AndroidManifest.xml index 276c4bea..d320d211 100644 --- a/ui/graphics/PdfRendererBasic/Application/src/main/AndroidManifest.xml +++ b/ui/graphics/PdfRendererBasic/Application/src/main/AndroidManifest.xml @@ -14,19 +14,21 @@ See the License for the specific language governing permissions and limitations under the License. --> +<manifest + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="com.example.android.pdfrendererbasic"> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.example.android.pdfrendererbasic" - android:versionCode="1" - android:versionName="1.0"> - - <application android:allowBackup="true" - android:label="@string/app_name" + <application + android:allowBackup="false" android:icon="@mipmap/ic_launcher" - android:theme="@style/Theme.PdfRendererBasic"> + android:label="@string/app_name" + android:theme="@style/Theme.PdfRendererBasic" + tools:ignore="GoogleAppIndexingWarning"> - <activity android:name=".MainActivity" - android:label="@string/app_name"> + <activity + android:name=".MainActivity" + android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> @@ -34,5 +36,4 @@ </activity> </application> - </manifest> diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/MainActivity.java b/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/MainActivity.java index 25781b79..0a59b7bb 100644 --- a/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/MainActivity.java +++ b/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/MainActivity.java @@ -16,25 +16,29 @@ package com.example.android.pdfrendererbasic; -import android.app.AlertDialog; +import android.app.Dialog; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.DialogFragment; + public class MainActivity extends AppCompatActivity { - public static final String FRAGMENT_PDF_RENDERER_BASIC = "pdf_renderer_basic"; + private static final String FRAGMENT_INFO = "info"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main_real); + setContentView(R.layout.main_activity); if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction() - .add(R.id.container, new PdfRendererBasicFragment(), - FRAGMENT_PDF_RENDERER_BASIC) - .commit(); + .add(R.id.container, new PdfRendererBasicFragment()) + .commitNow(); } } @@ -48,12 +52,23 @@ public class MainActivity extends AppCompatActivity { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_info: - new AlertDialog.Builder(this) - .setMessage(R.string.intro_message) - .setPositiveButton(android.R.string.ok, null) - .show(); + new InfoDialogFragment().show(getSupportFragmentManager(), FRAGMENT_INFO); return true; } return super.onOptionsItemSelected(item); } + + public static class InfoDialogFragment extends DialogFragment { + + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + return new AlertDialog.Builder(requireContext()) + .setMessage(R.string.intro_message) + .setPositiveButton(android.R.string.ok, null) + .show(); + } + + } + } diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragment.java b/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragment.java index 98f16941..2a933716 100644 --- a/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragment.java +++ b/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragment.java @@ -16,235 +16,75 @@ package com.example.android.pdfrendererbasic; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.pdf.PdfRenderer; +import android.app.Activity; import android.os.Bundle; -import android.os.ParcelFileDescriptor; -import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageView; -import android.widget.Toast; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.ViewModelProviders; /** - * This fragment has a big {@ImageView} that shows PDF pages, and 2 - * {@link android.widget.Button}s to move between pages. We use a - * {@link android.graphics.pdf.PdfRenderer} to render PDF pages as - * {@link android.graphics.Bitmap}s. + * This fragment has a big {@link ImageView} that shows PDF pages, and 2 + * {@link android.widget.Button}s to move between pages. */ -public class PdfRendererBasicFragment extends Fragment implements View.OnClickListener { +public class PdfRendererBasicFragment extends Fragment { - /** - * Key string for saving the state of current page index. - */ - private static final String STATE_CURRENT_PAGE_INDEX = "current_page_index"; + private PdfRendererBasicViewModel mViewModel; - /** - * The filename of the PDF. - */ - private static final String FILENAME = "sample.pdf"; - - /** - * File descriptor of the PDF. - */ - private ParcelFileDescriptor mFileDescriptor; - - /** - * {@link android.graphics.pdf.PdfRenderer} to render the PDF. - */ - private PdfRenderer mPdfRenderer; - - /** - * Page that is currently shown on the screen. - */ - private PdfRenderer.Page mCurrentPage; - - /** - * {@link android.widget.ImageView} that shows a PDF page as a {@link android.graphics.Bitmap} - */ - private ImageView mImageView; - - /** - * {@link android.widget.Button} to move to the previous page. - */ - private Button mButtonPrevious; - - /** - * {@link android.widget.Button} to move to the next page. - */ - private Button mButtonNext; - - /** - * PDF page index - */ - private int mPageIndex; - - public PdfRendererBasicFragment() { - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_pdf_renderer_basic, container, false); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - // Retain view references. - mImageView = (ImageView) view.findViewById(R.id.image); - mButtonPrevious = (Button) view.findViewById(R.id.previous); - mButtonNext = (Button) view.findViewById(R.id.next); - // Bind events. - mButtonPrevious.setOnClickListener(this); - mButtonNext.setOnClickListener(this); - - mPageIndex = 0; - // If there is a savedInstanceState (screen orientations, etc.), we restore the page index. - if (null != savedInstanceState) { - mPageIndex = savedInstanceState.getInt(STATE_CURRENT_PAGE_INDEX, 0); - } - } - - @Override - public void onStart() { - super.onStart(); - try { - openRenderer(getActivity()); - showPage(mPageIndex); - } catch (IOException e) { - e.printStackTrace(); - Toast.makeText(getActivity(), "Error! " + e.getMessage(), Toast.LENGTH_SHORT).show(); - } - } - - @Override - public void onStop() { - try { - closeRenderer(); - } catch (IOException e) { - e.printStackTrace(); + private final View.OnClickListener mOnClickListener = (view) -> { + switch (view.getId()) { + case R.id.previous: + if (mViewModel != null) { + mViewModel.showPrevious(); + } + break; + case R.id.next: + if (mViewModel != null) { + mViewModel.showNext(); + } + break; } - super.onStop(); - } + }; @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - if (null != mCurrentPage) { - outState.putInt(STATE_CURRENT_PAGE_INDEX, mCurrentPage.getIndex()); - } - } - - /** - * Sets up a {@link android.graphics.pdf.PdfRenderer} and related resources. - */ - private void openRenderer(Context context) throws IOException { - // In this sample, we read a PDF from the assets directory. - File file = new File(context.getCacheDir(), FILENAME); - if (!file.exists()) { - // Since PdfRenderer cannot handle the compressed asset file directly, we copy it into - // the cache directory. - InputStream asset = context.getAssets().open(FILENAME); - FileOutputStream output = new FileOutputStream(file); - final byte[] buffer = new byte[1024]; - int size; - while ((size = asset.read(buffer)) != -1) { - output.write(buffer, 0, size); - } - asset.close(); - output.close(); - } - mFileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); - // This is the PdfRenderer we use to render the PDF. - if (mFileDescriptor != null) { - mPdfRenderer = new PdfRenderer(mFileDescriptor); - } - } - - /** - * Closes the {@link android.graphics.pdf.PdfRenderer} and related resources. - * - * @throws java.io.IOException When the PDF file cannot be closed. - */ - private void closeRenderer() throws IOException { - if (null != mCurrentPage) { - mCurrentPage.close(); - } - mPdfRenderer.close(); - mFileDescriptor.close(); - } - - /** - * Shows the specified page of PDF to the screen. - * - * @param index The page index. - */ - private void showPage(int index) { - if (mPdfRenderer.getPageCount() <= index) { - return; - } - // Make sure to close the current page before opening another one. - if (null != mCurrentPage) { - mCurrentPage.close(); - } - // Use `openPage` to open a specific page in PDF. - mCurrentPage = mPdfRenderer.openPage(index); - // Important: the destination bitmap must be ARGB (not RGB). - Bitmap bitmap = Bitmap.createBitmap(mCurrentPage.getWidth(), mCurrentPage.getHeight(), - Bitmap.Config.ARGB_8888); - // Here, we render the page onto the Bitmap. - // To render a portion of the page, use the second and third parameter. Pass nulls to get - // the default result. - // Pass either RENDER_MODE_FOR_DISPLAY or RENDER_MODE_FOR_PRINT for the last parameter. - mCurrentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY); - // We are ready to show the Bitmap to user. - mImageView.setImageBitmap(bitmap); - updateUi(); - } - - /** - * Updates the state of 2 control buttons in response to the current page index. - */ - private void updateUi() { - int index = mCurrentPage.getIndex(); - int pageCount = mPdfRenderer.getPageCount(); - mButtonPrevious.setEnabled(0 != index); - mButtonNext.setEnabled(index + 1 < pageCount); - getActivity().setTitle(getString(R.string.app_name_with_index, index + 1, pageCount)); - } - - /** - * Gets the number of pages in the PDF. This method is marked as public for testing. - * - * @return The number of pages. - */ - public int getPageCount() { - return mPdfRenderer.getPageCount(); + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.pdf_renderer_basic_fragment, container, false); } @Override - public void onClick(View view) { - switch (view.getId()) { - case R.id.previous: { - // Move to the previous page - showPage(mCurrentPage.getIndex() - 1); - break; + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + // View references. + final ImageView image = view.findViewById(R.id.image); + final Button buttonPrevious = view.findViewById(R.id.previous); + final Button buttonNext = view.findViewById(R.id.next); + + // Bind data. + mViewModel = ViewModelProviders.of(this).get(PdfRendererBasicViewModel.class); + final LifecycleOwner viewLifecycleOwner = getViewLifecycleOwner(); + mViewModel.getPageInfo().observe(viewLifecycleOwner, pageInfo -> { + if (pageInfo == null) { + return; } - case R.id.next: { - // Move to the next page - showPage(mCurrentPage.getIndex() + 1); - break; + final Activity activity = getActivity(); + if (activity != null) { + activity.setTitle(getString(R.string.app_name_with_index, + pageInfo.index + 1, pageInfo.count)); } - } + }); + mViewModel.getPageBitmap().observe(viewLifecycleOwner, image::setImageBitmap); + mViewModel.getPreviousEnabled().observe(viewLifecycleOwner, buttonPrevious::setEnabled); + mViewModel.getNextEnabled().observe(viewLifecycleOwner, buttonNext::setEnabled); + + // Bind events. + buttonPrevious.setOnClickListener(mOnClickListener); + buttonNext.setOnClickListener(mOnClickListener); } } diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicViewModel.java b/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicViewModel.java new file mode 100644 index 00000000..cb638c04 --- /dev/null +++ b/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicViewModel.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.pdfrendererbasic; + +import android.app.Application; +import android.graphics.Bitmap; +import android.graphics.pdf.PdfRenderer; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import androidx.annotation.WorkerThread; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +/** + * This holds all the data we need for this sample app. + * <p> + * We use a {@link android.graphics.pdf.PdfRenderer} to render PDF pages as + * {@link android.graphics.Bitmap}s. + */ +public class PdfRendererBasicViewModel extends AndroidViewModel { + + private static final String TAG = "PdfRendererBasic"; + + /** + * The filename of the PDF. + */ + private static final String FILENAME = "sample.pdf"; + + private final MutableLiveData<PageInfo> mPageInfo = new MutableLiveData<>(); + private final MutableLiveData<Bitmap> mPageBitmap = new MutableLiveData<>(); + private final MutableLiveData<Boolean> mPreviousEnabled = new MutableLiveData<>(); + private final MutableLiveData<Boolean> mNextEnabled = new MutableLiveData<>(); + + private final Executor mExecutor; + private ParcelFileDescriptor mFileDescriptor; + private PdfRenderer mPdfRenderer; + private PdfRenderer.Page mCurrentPage; + private boolean mCleared; + + @SuppressWarnings("unused") + public PdfRendererBasicViewModel(Application application) { + this(application, false); + } + + PdfRendererBasicViewModel(Application application, boolean useInstantExecutor) { + super(application); + if (useInstantExecutor) { + mExecutor = Runnable::run; + } else { + mExecutor = Executors.newSingleThreadExecutor(); + } + mExecutor.execute(() -> { + try { + openPdfRenderer(); + showPage(0); + if (mCleared) { + closePdfRenderer(); + } + } catch (IOException e) { + Log.e(TAG, "Failed to open PdfRenderer", e); + } + }); + } + + @Override + protected void onCleared() { + super.onCleared(); + mExecutor.execute(() -> { + try { + closePdfRenderer(); + mCleared = true; + } catch (IOException e) { + Log.i(TAG, "Failed to close PdfRenderer", e); + } + }); + } + + LiveData<PageInfo> getPageInfo() { + return mPageInfo; + } + + LiveData<Bitmap> getPageBitmap() { + return mPageBitmap; + } + + LiveData<Boolean> getPreviousEnabled() { + return mPreviousEnabled; + } + + LiveData<Boolean> getNextEnabled() { + return mNextEnabled; + } + + void showPrevious() { + if (mPdfRenderer == null || mCurrentPage == null) { + return; + } + final int index = mCurrentPage.getIndex(); + if (index > 0) { + mExecutor.execute(() -> showPage(index - 1)); + } + } + + void showNext() { + if (mPdfRenderer == null || mCurrentPage == null) { + return; + } + final int index = mCurrentPage.getIndex(); + if (index + 1 < mPdfRenderer.getPageCount()) { + mExecutor.execute(() -> showPage(index + 1)); + } + } + + @WorkerThread + private void openPdfRenderer() throws IOException { + final File file = new File(getApplication().getCacheDir(), FILENAME); + if (!file.exists()) { + // Since PdfRenderer cannot handle the compressed asset file directly, we copy it into + // the cache directory. + final InputStream asset = getApplication().getAssets().open(FILENAME); + final FileOutputStream output = new FileOutputStream(file); + final byte[] buffer = new byte[1024]; + int size; + while ((size = asset.read(buffer)) != -1) { + output.write(buffer, 0, size); + } + asset.close(); + output.close(); + } + mFileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); + if (mFileDescriptor != null) { + mPdfRenderer = new PdfRenderer(mFileDescriptor); + } + } + + @WorkerThread + private void closePdfRenderer() throws IOException { + if (mCurrentPage != null) { + mCurrentPage.close(); + } + if (mPdfRenderer != null) { + mPdfRenderer.close(); + } + if (mFileDescriptor != null) { + mFileDescriptor.close(); + } + } + + @WorkerThread + private void showPage(int index) { + // Make sure to close the current page before opening another one. + if (null != mCurrentPage) { + mCurrentPage.close(); + } + // Use `openPage` to open a specific page in PDF. + mCurrentPage = mPdfRenderer.openPage(index); + // Important: the destination bitmap must be ARGB (not RGB). + final Bitmap bitmap = Bitmap.createBitmap(mCurrentPage.getWidth(), mCurrentPage.getHeight(), + Bitmap.Config.ARGB_8888); + // Here, we render the page onto the Bitmap. + // To render a portion of the page, use the second and third parameter. Pass nulls to get + // the default result. + // Pass either RENDER_MODE_FOR_DISPLAY or RENDER_MODE_FOR_PRINT for the last parameter. + mCurrentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY); + mPageBitmap.postValue(bitmap); + final int count = mPdfRenderer.getPageCount(); + mPageInfo.postValue(new PageInfo(index, count)); + mPreviousEnabled.postValue(index > 0); + mNextEnabled.postValue(index + 1 < count); + } + + static class PageInfo { + final int index; + final int count; + + PageInfo(int index, int count) { + this.index = index; + this.count = count; + } + } + +} diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/res/layout/activity_main_real.xml b/ui/graphics/PdfRendererBasic/Application/src/main/res/layout/main_activity.xml index dcd52bea..60a42be2 100644 --- a/ui/graphics/PdfRendererBasic/Application/src/main/res/layout/activity_main_real.xml +++ b/ui/graphics/PdfRendererBasic/Application/src/main/res/layout/main_activity.xml @@ -14,10 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. --> -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".MainActivity" - tools:ignore="MergeRootFrame" /> + tools:context=".MainActivity" /> diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/res/layout/fragment_pdf_renderer_basic.xml b/ui/graphics/PdfRendererBasic/Application/src/main/res/layout/pdf_renderer_basic_fragment.xml index 7ecfac36..7ecfac36 100644 --- a/ui/graphics/PdfRendererBasic/Application/src/main/res/layout/fragment_pdf_renderer_basic.xml +++ b/ui/graphics/PdfRendererBasic/Application/src/main/res/layout/pdf_renderer_basic_fragment.xml diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/res/values/strings.xml b/ui/graphics/PdfRendererBasic/Application/src/main/res/values/strings.xml index e0182fd3..995a82e9 100644 --- a/ui/graphics/PdfRendererBasic/Application/src/main/res/values/strings.xml +++ b/ui/graphics/PdfRendererBasic/Application/src/main/res/values/strings.xml @@ -16,7 +16,9 @@ --> <resources> + <string name="app_name">PdfRendererBasic</string> <string name="app_name_with_index">PdfRendererBasic (%1$d/%2$d)</string> + <string name="intro_message">This sample demonstrates how to use PdfRenderer to display PDF documents on the screen.</string> <string name="info">Info</string> <string name="previous">Previous</string> <string name="next">Next</string> diff --git a/ui/graphics/PdfRendererBasic/Application/tests/AndroidManifest.xml b/ui/graphics/PdfRendererBasic/Application/tests/AndroidManifest.xml deleted file mode 100644 index 54829c78..00000000 --- a/ui/graphics/PdfRendererBasic/Application/tests/AndroidManifest.xml +++ /dev/null @@ -1,41 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2014 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --> -<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us --> -<manifest - package="com.example.android.pdfrendererbasic.tests" - xmlns:android="http://schemas.android.com/apk/res/android" - android:versionCode="1" - android:versionName="1.0"> - - <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle --> - - <!-- We add an application tag here just so that we can indicate that - this package needs to link against the android.test library, - which is needed when building test cases. --> - <application> - <uses-library android:name="android.test.runner"/> - </application> - - <!-- - Specifies the instrumentation test runner used to run the tests. - --> - <instrumentation - android:name="android.test.InstrumentationTestRunner" - android:label="Tests for com.example.android.pdfrendererbasic" - android:targetPackage="com.example.android.pdfrendererbasic"/> - -</manifest> diff --git a/ui/graphics/PdfRendererBasic/Application/tests/src/com/example/android/pdfrendererbasic/tests/PdfRendererBasicFragmentTests.java b/ui/graphics/PdfRendererBasic/Application/tests/src/com/example/android/pdfrendererbasic/tests/PdfRendererBasicFragmentTests.java deleted file mode 100644 index 0f94cbf8..00000000 --- a/ui/graphics/PdfRendererBasic/Application/tests/src/com/example/android/pdfrendererbasic/tests/PdfRendererBasicFragmentTests.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.pdfrendererbasic.tests; - -import android.content.pm.ActivityInfo; -import android.test.ActivityInstrumentationTestCase2; -import android.test.TouchUtils; -import android.test.suitebuilder.annotation.LargeTest; -import android.view.View; -import android.widget.Button; - -import com.example.android.pdfrendererbasic.MainActivity; -import com.example.android.pdfrendererbasic.PdfRendererBasicFragment; -import com.example.android.pdfrendererbasic.R; - -/** - * Tests for PdfRendererBasic sample. - */ -public class PdfRendererBasicFragmentTests extends ActivityInstrumentationTestCase2<MainActivity> { - - private MainActivity mActivity; - private PdfRendererBasicFragment mFragment; - - private Button mButtonPrevious; - private Button mButtonNext; - - public PdfRendererBasicFragmentTests() { - super(MainActivity.class); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - mActivity = getActivity(); - mFragment = (PdfRendererBasicFragment) mActivity.getFragmentManager() - .findFragmentByTag(MainActivity.FRAGMENT_PDF_RENDERER_BASIC); - } - - @LargeTest - public void testActivityTitle() { - // The title of the activity should be "PdfRendererBasic (1/10)" at first - String expectedActivityTitle = mActivity.getString(R.string.app_name_with_index, 1, - mFragment.getPageCount()); - assertEquals(expectedActivityTitle, mActivity.getTitle()); - } - - @LargeTest - public void testButtons_previousDisabledAtFirst() { - setUpButtons(); - // Check that the previous button is disabled at first - assertFalse(mButtonPrevious.isEnabled()); - // The next button should be enabled - assertTrue(mButtonNext.isEnabled()); - } - - @LargeTest - public void testButtons_bothEnabledInMiddle() { - setUpButtons(); - turnPages(1); - // Two buttons should be both enabled - assertTrue(mButtonPrevious.isEnabled()); - assertTrue(mButtonNext.isEnabled()); - } - - @LargeTest - public void testButtons_nextDisabledLastPage() { - setUpButtons(); - int pageCount = mFragment.getPageCount(); - // Click till it reaches the last page - turnPages(pageCount - 1); - // Check the page count - String expectedActivityTitle = mActivity.getString(R.string.app_name_with_index, - pageCount, pageCount); - assertEquals(expectedActivityTitle, mActivity.getTitle()); - // The previous button should be enabled - assertTrue(mButtonPrevious.isEnabled()); - // Check that the next button is disabled - assertFalse(mButtonNext.isEnabled()); - } - - @LargeTest - public void testOrientationChangePreserveState() { - mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - setUpButtons(); - turnPages(1); - int pageCount = mFragment.getPageCount(); - String expectedActivityTitle = mActivity.getString(R.string.app_name_with_index, - 2, pageCount); - assertEquals(expectedActivityTitle, mActivity.getTitle()); - mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - // Check that the title is the same after orientation change - assertEquals(expectedActivityTitle, mActivity.getTitle()); - } - - /** - * Prepares references to the buttons "Previous" and "Next". - */ - private void setUpButtons() { - View view = mFragment.getView(); - assertNotNull(view); - mButtonPrevious = (Button) view.findViewById(R.id.previous); - assertNotNull(mButtonPrevious); - mButtonNext = (Button) view.findViewById(R.id.next); - assertNotNull(mButtonNext); - } - - /** - * Click the "Next" button to turn the pages. - * - * @param count The number of times to turn pages. - */ - private void turnPages(int count) { - for (int i = 0; i < count; ++i) { - TouchUtils.clickView(this, mButtonNext); - } - } - -} diff --git a/ui/graphics/PdfRendererBasic/build.gradle b/ui/graphics/PdfRendererBasic/build.gradle index be1fa823..93ddf8c4 100644 --- a/ui/graphics/PdfRendererBasic/build.gradle +++ b/ui/graphics/PdfRendererBasic/build.gradle @@ -1,14 +1,29 @@ +buildscript { + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.3.0' + } +} - +allprojects { + repositories { + google() + jcenter() + } +} // BEGIN_EXCLUDE import com.example.android.samples.build.SampleGenPlugin + apply plugin: SampleGenPlugin samplegen { - pathToBuild "../../../../../build" - pathToSamplesCommon "../../../common" + pathToBuild "../../../../../build" + pathToSamplesCommon "../../../common" } apply from: "../../../../../build/build.gradle" // END_EXCLUDE diff --git a/ui/graphics/PdfRendererBasic/gradle.properties b/ui/graphics/PdfRendererBasic/gradle.properties new file mode 100644 index 00000000..795e261a --- /dev/null +++ b/ui/graphics/PdfRendererBasic/gradle.properties @@ -0,0 +1,14 @@ +# Project-wide Gradle settings. + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +org.gradle.parallel=true + +android.useAndroidX=true +android.enableJetifier=true diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/build.gradle b/ui/graphics/PdfRendererBasic/kotlinApp/Application/build.gradle index 44d34d58..a1be48c4 100644 --- a/ui/graphics/PdfRendererBasic/kotlinApp/Application/build.gradle +++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/build.gradle @@ -1,35 +1,39 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' android { - compileSdkVersion rootProject.ext.compileSdkVersion + compileSdkVersion 28 + defaultConfig { - applicationId "com.example.android.pdfrendererbasic" - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + applicationId 'com.example.android.pdfrendererbasic' + minSdkVersion 21 + targetSdkVersion 28 versionCode 1 - versionName "1.0" + versionName '1.0' + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + + testOptions { + unitTests { + returnDefaultValues = true + includeAndroidResources = true } } } dependencies { - implementation "com.android.support:appcompat-v7:$rootProject.ext.supportLibVersion" - implementation "com.android.support:support-v4:$rootProject.ext.supportLibVersion" - implementation "org.jetbrains.kotlin:kotlin-stdlib:$rootProject.ext.kotlinVersion" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.0' + + implementation 'androidx.appcompat:appcompat:1.0.2' + + def lifecycle_version = '2.0.0' + implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" + androidTestImplementation "androidx.arch.core:core-testing:$lifecycle_version" - // Testing dependencies - androidTestImplementation "com.android.support.test.espresso:espresso-contrib:$rootProject.ext.espressoVersion" - androidTestImplementation "com.android.support.test.espresso:espresso-core:$rootProject.ext.espressoVersion" - androidTestCompile "com.android.support:support-annotations:$rootProject.ext.supportLibVersion" - androidTestCompile "com.android.support.test:runner:$rootProject.ext.supportTestVersion" - androidTestCompile "com.android.support.test:rules:$rootProject.ext.supportTestVersion" - testImplementation "junit:junit:$rootProject.ext.junitVersion" + testImplementation 'com.google.truth:truth:0.42' + testImplementation 'androidx.test:core:1.1.0' + testImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.ext:truth:1.1.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' } diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/androidTest/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragmentTests.kt b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/androidTest/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragmentTests.kt deleted file mode 100644 index b2abc69b..00000000 --- a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/androidTest/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragmentTests.kt +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.pdfrendererbasic - -import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE -import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT -import android.support.test.espresso.Espresso.onView -import android.support.test.espresso.action.ViewActions.click -import android.support.test.espresso.matcher.ViewMatchers.withId -import android.support.test.rule.ActivityTestRule -import android.support.test.runner.AndroidJUnit4 -import android.widget.Button -import org.junit.Assert.assertEquals -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith - -/** - * Tests for PdfRendererBasic sample. - */ -@RunWith(AndroidJUnit4::class) -class PdfRendererBasicFragmentTests { - - private lateinit var fragment: PdfRendererBasicFragment - private lateinit var btnPrevious: Button - private lateinit var btnNext: Button - - @Rule @JvmField - val activityTestRule = ActivityTestRule(MainActivity::class.java) - - @Before fun before() { - activityTestRule.activity.supportFragmentManager.beginTransaction() - fragment = activityTestRule.activity.supportFragmentManager - .findFragmentByTag(FRAGMENT_PDF_RENDERER_BASIC) as PdfRendererBasicFragment - } - - @Test fun testActivityTitle() { - // The title of the activity should be "PdfRendererBasic (1/10)" at first - val expectedActivityTitle = activityTestRule.activity.getString( - R.string.app_name_with_index, 1, fragment.getPageCount()) - assertEquals(expectedActivityTitle, activityTestRule.activity.title) - } - - @Test fun testButtons_previousDisabledAtFirst() { - setUpButtons() - // Check that the previous button is disabled at first - assertFalse(btnPrevious.isEnabled) - // The next button should be enabled - assertTrue(btnNext.isEnabled) - } - - @Test fun testButtons_bothEnabledInMiddle() { - setUpButtons() - turnPages(1) - // Two buttons should be both enabled - assertTrue(btnPrevious.isEnabled) - assertTrue(btnNext.isEnabled) - } - - @Test fun testButtons_nextDisabledLastPage() { - setUpButtons() - val pageCount = fragment.getPageCount() - // Click till it reaches the last page - turnPages(pageCount - 1) - // Check the page count - val expectedActivityTitle = activityTestRule.activity.getString( - R.string.app_name_with_index, pageCount, pageCount) - assertEquals(expectedActivityTitle, activityTestRule.activity.title) - // The previous button should be enabled - assertTrue(btnPrevious.isEnabled) - // Check that the next button is disabled - assertFalse(btnNext.isEnabled) - } - - @Test fun testOrientationChangePreserveState() { - activityTestRule.activity.requestedOrientation = SCREEN_ORIENTATION_PORTRAIT - setUpButtons() - turnPages(1) - val pageCount = fragment.getPageCount() - val expectedActivityTitle = activityTestRule.activity - .getString(R.string.app_name_with_index, 2, pageCount) - assertEquals(expectedActivityTitle, activityTestRule.activity.title) - activityTestRule.activity.requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE - // Check that the title is the same after orientation change - assertEquals(expectedActivityTitle, activityTestRule.activity.title) - } - - /** - * Prepares references to the buttons "Previous" and "Next". - */ - private fun setUpButtons() { - val view = fragment.view ?: return - btnPrevious = view.findViewById(R.id.previous) - btnNext = view.findViewById(R.id.next) - } - - /** - * Click the "Next" button to turn the pages. - * - * @param count The number of times to turn pages. - */ - private fun turnPages(count: Int) { - for (i in 0 until count) { - onView(withId(R.id.next)).perform(click()) - } - } - -} diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/androidTest/java/com/example/android/pdfrendererbasic/PdfRendererBasicViewModelTest.kt b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/androidTest/java/com/example/android/pdfrendererbasic/PdfRendererBasicViewModelTest.kt new file mode 100644 index 00000000..c2d7b26a --- /dev/null +++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/androidTest/java/com/example/android/pdfrendererbasic/PdfRendererBasicViewModelTest.kt @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.pdfrendererbasic + +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.test.core.app.ApplicationProvider +import androidx.test.runner.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class PdfRendererBasicViewModelTest { + + @get:Rule + val instantTaskExecutorRule = InstantTaskExecutorRule() + + private val viewModel = PdfRendererBasicViewModel( + ApplicationProvider.getApplicationContext(), true) + + @Test + fun allPages() { + assertThat(viewModel).isNotNull() + assertThat(viewModel.pageInfo.value).isEqualTo(0 to 10) + assertThat(viewModel.previousEnabled.value).isFalse() + assertThat(viewModel.nextEnabled.value).isTrue() + assertThat(viewModel.pageBitmap.value).isNotNull() + repeat(9) { viewModel.showNext() } + assertThat(viewModel.pageInfo.value).isEqualTo(9 to 10) + assertThat(viewModel.previousEnabled.value).isTrue() + assertThat(viewModel.nextEnabled.value).isFalse() + assertThat(viewModel.pageBitmap.value).isNotNull() + } + +} diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/AndroidManifest.xml b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/AndroidManifest.xml index de585c9c..22500853 100644 --- a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/AndroidManifest.xml +++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/AndroidManifest.xml @@ -14,17 +14,21 @@ See the License for the specific language governing permissions and limitations under the License. --> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" +<manifest + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" package="com.example.android.pdfrendererbasic"> - <application android:allowBackup="false" - android:label="@string/app_name" + <application + android:allowBackup="false" android:icon="@mipmap/ic_launcher" - android:theme="@style/Theme.PdfRendererBasic"> + android:label="@string/app_name" + android:theme="@style/Theme.PdfRendererBasic" + tools:ignore="GoogleAppIndexingWarning"> - <activity android:name=".MainActivity" - android:label="@string/app_name"> + <activity + android:name=".MainActivity" + android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> @@ -32,5 +36,4 @@ </activity> </application> - </manifest> diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/MainActivity.kt b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/MainActivity.kt index 1d253bd1..dd0ffc59 100644 --- a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/MainActivity.kt +++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/MainActivity.kt @@ -16,24 +16,27 @@ package com.example.android.pdfrendererbasic -import android.app.AlertDialog +import android.app.Dialog import android.os.Bundle -import android.support.v7.app.AppCompatActivity import android.view.Menu import android.view.MenuItem - -val FRAGMENT_PDF_RENDERER_BASIC = "pdf_renderer_basic" +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.DialogFragment class MainActivity : AppCompatActivity() { + companion object { + const val FRAGMENT_INFO = "info" + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main_real) + setContentView(R.layout.main_activity) if (savedInstanceState == null) { supportFragmentManager.beginTransaction() - .add(R.id.container, PdfRendererBasicFragment(), FRAGMENT_PDF_RENDERER_BASIC) - .commit() + .replace(R.id.container, PdfRendererBasicFragment()) + .commitNow() } } @@ -45,14 +48,20 @@ class MainActivity : AppCompatActivity() { override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.action_info -> { - AlertDialog.Builder(this) - .setMessage(R.string.intro_message) - .setPositiveButton(android.R.string.ok, null) - .show() + InfoFragment().show(supportFragmentManager, FRAGMENT_INFO) return true } else -> super.onOptionsItemSelected(item) } } + class InfoFragment : DialogFragment() { + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return AlertDialog.Builder(requireContext()) + .setMessage(R.string.intro_message) + .setPositiveButton(android.R.string.ok, null) + .show() + } + } + } diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragment.kt b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragment.kt index 89e1cfd0..1ffc5817 100644 --- a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragment.kt +++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragment.kt @@ -16,222 +16,47 @@ package com.example.android.pdfrendererbasic -import android.content.Context -import android.graphics.Bitmap -import android.graphics.Bitmap.createBitmap -import android.graphics.pdf.PdfRenderer import android.os.Bundle -import android.os.ParcelFileDescriptor -import android.support.v4.app.Fragment -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Button import android.widget.ImageView -import java.io.File -import java.io.FileOutputStream -import java.io.IOException +import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders /** * This fragment has a big [ImageView] that shows PDF pages, and 2 [Button]s to move between pages. - * We use a [PdfRenderer] to render PDF pages as [Bitmap]s. */ -class PdfRendererBasicFragment : Fragment(), View.OnClickListener { +class PdfRendererBasicFragment : Fragment() { - /** - * The filename of the PDF. - */ - private val FILENAME = "sample.pdf" - - /** - * Key string for saving the state of current page index. - */ - private val STATE_CURRENT_PAGE_INDEX = "current_page_index" - - /** - * String for logging. - */ - private val TAG = "PdfRendererBasicFragment" - - /** - * The initial page index of the PDF. - */ - private val INITIAL_PAGE_INDEX = 0 - - /** - * File descriptor of the PDF. - */ - private lateinit var fileDescriptor: ParcelFileDescriptor - - /** - * [PdfRenderer] to render the PDF. - */ - private lateinit var pdfRenderer: PdfRenderer - - /** - * Page that is currently shown on the screen. - */ - private lateinit var currentPage: PdfRenderer.Page - - /** - * [ImageView] that shows a PDF page as a [Bitmap]. - */ - private lateinit var imageView: ImageView - - /** - * [Button] to move to the previous page. - */ - private lateinit var btnPrevious: Button - - /** - * [Button] to move to the next page. - */ - private lateinit var btnNext: Button - - /** - * PDF page index. - */ - private var pageIndex: Int = INITIAL_PAGE_INDEX - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - return inflater.inflate(R.layout.fragment_pdf_renderer_basic, container, false) + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.pdf_renderer_basic_fragment, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - imageView = view.findViewById(R.id.image) - btnPrevious = view.findViewById<Button>(R.id.previous).also { it.setOnClickListener(this) } - btnNext = view.findViewById<Button>(R.id.next).also { it.setOnClickListener(this)} - - // If there is a savedInstanceState (screen orientations, etc.), we restore the page index. - if (savedInstanceState != null) { - pageIndex = savedInstanceState.getInt(STATE_CURRENT_PAGE_INDEX, INITIAL_PAGE_INDEX) - } else { - pageIndex = INITIAL_PAGE_INDEX - } - } - - override fun onStart() { - super.onStart() - try { - openRenderer(activity) - showPage(pageIndex) - } catch (e: IOException) { - Log.d(TAG, e.toString()) - } - } - - override fun onStop() { - try { - closeRenderer() - } catch (e: IOException) { - Log.d(TAG, e.toString()) - } - super.onStop() - } - - override fun onSaveInstanceState(outState: Bundle) { - outState.putInt(STATE_CURRENT_PAGE_INDEX, currentPage.index) - super.onSaveInstanceState(outState) - } - - /** - * Sets up a [PdfRenderer] and related resources. - */ - @Throws(IOException::class) - private fun openRenderer(context: Context?) { - if (context == null) return - - // In this sample, we read a PDF from the assets directory. - val file = File(context.cacheDir, FILENAME) - if (!file.exists()) { - // Since PdfRenderer cannot handle the compressed asset file directly, we copy it into - // the cache directory. - val asset = context.assets.open(FILENAME) - val output = FileOutputStream(file) - val buffer = ByteArray(1024) - var size = asset.read(buffer) - while (size != -1) { - output.write(buffer, 0, size) - size = asset.read(buffer) - } - asset.close() - output.close() - } - fileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY) - // This is the PdfRenderer we use to render the PDF. - pdfRenderer = PdfRenderer(fileDescriptor) - currentPage = pdfRenderer.openPage(pageIndex) - } - - /** - * Closes the [PdfRenderer] and related resources. - * - * @throws IOException When the PDF file cannot be closed. - */ - @Throws(IOException::class) - private fun closeRenderer() { - currentPage.close() - pdfRenderer.close() - fileDescriptor.close() - } - - /** - * Shows the specified page of PDF to the screen. - * - * @param index The page index. - */ - private fun showPage(index: Int) { - if (pdfRenderer.pageCount <= index) return - - // Make sure to close the current page before opening another one. - currentPage.close() - // Use `openPage` to open a specific page in PDF. - currentPage = pdfRenderer.openPage(index) - // Important: the destination bitmap must be ARGB (not RGB). - val bitmap = createBitmap(currentPage.width, currentPage.height, Bitmap.Config.ARGB_8888) - // Here, we render the page onto the Bitmap. - // To render a portion of the page, use the second and third parameter. Pass nulls to get - // the default result. - // Pass either RENDER_MODE_FOR_DISPLAY or RENDER_MODE_FOR_PRINT for the last parameter. - currentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY) - // We are ready to show the Bitmap to user. - imageView.setImageBitmap(bitmap) - updateUi() - } - - /** - * Updates the state of 2 control buttons in response to the current page index. - */ - private fun updateUi() { - val index = currentPage.index - val pageCount = pdfRenderer.pageCount - btnPrevious.isEnabled = (0 != index) - btnNext.isEnabled = (index + 1 < pageCount) - activity?.title = getString(R.string.app_name_with_index, index + 1, pageCount) - } - - /** - * Returns the page count of of the PDF. - */ - fun getPageCount() = pdfRenderer.pageCount - - override fun onClick(view: View) { - when (view.id) { - R.id.previous -> { - // Move to the previous page/ - showPage(currentPage.index - 1) - } - R.id.next -> { - // Move to the next page. - showPage(currentPage.index + 1) - } - } + // View references. + val image: ImageView = view.findViewById(R.id.image) + val buttonPrevious: Button = view.findViewById(R.id.previous) + val buttonNext: Button = view.findViewById(R.id.next) + + // Bind data. + val viewModel = ViewModelProviders.of(this).get(PdfRendererBasicViewModel::class.java) + viewModel.pageInfo.observe(viewLifecycleOwner, Observer { (index, count) -> + activity?.title = getString(R.string.app_name_with_index, index + 1, count) + }) + viewModel.pageBitmap.observe(viewLifecycleOwner, Observer { image.setImageBitmap(it) }) + viewModel.previousEnabled.observe(viewLifecycleOwner, Observer { + buttonPrevious.isEnabled = it + }) + viewModel.nextEnabled.observe(viewLifecycleOwner, Observer { + buttonNext.isEnabled = it + }) + + // Bind events. + buttonPrevious.setOnClickListener { viewModel.showPrevious() } + buttonNext.setOnClickListener { viewModel.showNext() } } } diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicViewModel.kt b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicViewModel.kt new file mode 100644 index 00000000..6324cce3 --- /dev/null +++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicViewModel.kt @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.pdfrendererbasic + +import android.app.Application +import android.graphics.Bitmap +import android.graphics.pdf.PdfRenderer +import android.os.ParcelFileDescriptor +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.asCoroutineDispatcher +import kotlinx.coroutines.launch +import java.io.File +import java.util.concurrent.Executor +import java.util.concurrent.Executors + +class PdfRendererBasicViewModel @JvmOverloads constructor( + application: Application, + useInstantExecutor: Boolean = false +) : AndroidViewModel(application) { + + companion object { + const val FILENAME = "sample.pdf" + } + + private val job = Job() + private val executor = if (useInstantExecutor) { + Executor { it.run() } + } else { + Executors.newSingleThreadExecutor() + } + private val scope = CoroutineScope(executor.asCoroutineDispatcher() + job) + + private var fileDescriptor: ParcelFileDescriptor? = null + private var pdfRenderer: PdfRenderer? = null + private var currentPage: PdfRenderer.Page? = null + private var cleared = false + + private val _pageBitmap = MutableLiveData<Bitmap>() + val pageBitmap: LiveData<Bitmap> + get() = _pageBitmap + + private val _previousEnabled = MutableLiveData<Boolean>() + val previousEnabled: LiveData<Boolean> + get() = _previousEnabled + + private val _nextEnabled = MutableLiveData<Boolean>() + val nextEnabled: LiveData<Boolean> + get() = _nextEnabled + + private val _pageInfo = MutableLiveData<Pair<Int, Int>>() + val pageInfo: LiveData<Pair<Int, Int>> + get() = _pageInfo + + init { + scope.launch { + openPdfRenderer() + showPage(0) + if (cleared) { + closePdfRenderer() + } + } + } + + override fun onCleared() { + super.onCleared() + scope.launch { + closePdfRenderer() + cleared = true + job.cancel() + } + } + + fun showPrevious() { + scope.launch { + currentPage?.let { page -> + if (page.index > 0) { + showPage(page.index - 1) + } + } + } + } + + fun showNext() { + scope.launch { + pdfRenderer?.let { renderer -> + currentPage?.let { page -> + if (page.index + 1 < renderer.pageCount) { + showPage(page.index + 1) + } + } + } + } + } + + private fun openPdfRenderer() { + val application = getApplication<Application>() + val file = File(application.cacheDir, FILENAME) + if (!file.exists()) { + application.assets.open(FILENAME).use { asset -> + file.writeBytes(asset.readBytes()) + } + } + fileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY).also { + pdfRenderer = PdfRenderer(it) + } + } + + private fun showPage(index: Int) { + // Make sure to close the current page before opening another one. + currentPage?.let { page -> + currentPage = null + page.close() + } + pdfRenderer?.let { renderer -> + // Use `openPage` to open a specific page in PDF. + val page = renderer.openPage(index).also { + currentPage = it + } + // Important: the destination bitmap must be ARGB (not RGB). + val bitmap = Bitmap.createBitmap(page.width, page.height, Bitmap.Config.ARGB_8888) + // Here, we render the page onto the Bitmap. + // To render a portion of the page, use the second and third parameter. Pass nulls to get + // the default result. + // Pass either RENDER_MODE_FOR_DISPLAY or RENDER_MODE_FOR_PRINT for the last parameter. + page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY) + _pageBitmap.postValue(bitmap) + val count = renderer.pageCount + _pageInfo.postValue(index to count) + _previousEnabled.postValue(index > 0) + _nextEnabled.postValue(index + 1 < count) + } + } + + private fun closePdfRenderer() { + currentPage?.close() + pdfRenderer?.close() + fileDescriptor?.close() + } + +} diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/layout/activity_main_real.xml b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/layout/activity_main_real.xml deleted file mode 100644 index 5d130ff5..00000000 --- a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/layout/activity_main_real.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - Copyright 2017 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - android:id="@+id/container" - android:layout_width="match_parent" - android:layout_height="match_parent" - tools:context=".MainActivity" - tools:ignore="MergeRootFrame" /> diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/layout/main_activity.xml b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/layout/main_activity.xml new file mode 100644 index 00000000..a613a72c --- /dev/null +++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/layout/main_activity.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/container" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context=".MainActivity" /> diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/layout/fragment_pdf_renderer_basic.xml b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/layout/pdf_renderer_basic_fragment.xml index aa8a9e1a..719502ed 100644 --- a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/layout/fragment_pdf_renderer_basic.xml +++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/layout/pdf_renderer_basic_fragment.xml @@ -1,18 +1,18 @@ -<?xml version="1.0" encoding="UTF-8"?> +<?xml version="1.0" encoding="utf-8"?> <!-- - Copyright 2017 The Android Open Source Project + Copyright (C) 2017 The Android Open Source Project - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" @@ -52,7 +52,6 @@ android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/next" /> - </LinearLayout> </LinearLayout> diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/values/strings.xml b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/values/strings.xml index 55f04f91..04968e4d 100644 --- a/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/values/strings.xml +++ b/ui/graphics/PdfRendererBasic/kotlinApp/Application/src/main/res/values/strings.xml @@ -15,19 +15,10 @@ limitations under the License. --> <resources> - <string name="app_name">PdfRendererBasic</string> <string name="app_name_with_index">PdfRendererBasic (%1$d/%2$d)</string> <string name="info">Info</string> <string name="previous">Previous</string> <string name="next">Next</string> - <string name="intro_message"> - <![CDATA[ - - - This sample demonstrates how to use PdfRenderer to display PDF documents on the screen. - - - ]]> - </string> + <string name="intro_message">This sample demonstrates how to use PdfRenderer to display PDF documents on the screen</string> </resources> diff --git a/ui/graphics/PdfRendererBasic/kotlinApp/build.gradle b/ui/graphics/PdfRendererBasic/kotlinApp/build.gradle index daa90118..4086415a 100644 --- a/ui/graphics/PdfRendererBasic/kotlinApp/build.gradle +++ b/ui/graphics/PdfRendererBasic/kotlinApp/build.gradle @@ -1,22 +1,13 @@ buildscript { - ext { - compileSdkVersion = 27 - minSdkVersion = 24 - targetSdkVersion = 27 - - espressoVersion = '3.0.1' - junitVersion = '4.12' - kotlinVersion = '1.3.11' - supportLibVersion = '27.0.2' - supportTestVersion = '1.0.1' - } + ext.kotlin_version = '1.3.11' repositories { google() jcenter() } + dependencies { classpath 'com.android.tools.build:gradle:3.3.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -26,7 +17,3 @@ allprojects { jcenter() } } - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/ui/graphics/PdfRendererBasic/template-params.xml b/ui/graphics/PdfRendererBasic/template-params.xml index 81ea8268..3d79c17e 100644 --- a/ui/graphics/PdfRendererBasic/template-params.xml +++ b/ui/graphics/PdfRendererBasic/template-params.xml @@ -33,7 +33,8 @@ </intro> </strings> - <template src="base"/> + <template src="base-build"/> + <androidX>true</androidX> <metadata> <status>PUBLISHED</status> |