• R/O
  • HTTP
  • SSH
  • HTTPS

提交

标签
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Simple Notepad Application for Android OS


Commit MetaInfo

修订版abf32354df425d51d5cfde0611973e0b9ddbc2aa (tree)
时间2016-05-08 17:04:46
作者Masahiko, SAWAI <say@user...>
CommiterMasahiko, SAWAI

Log Message

Added runtime permission support for Android 6.0

更改概述

差异

--- a/notepad-app-level-11/src/main/java/org/routine_work/notepad/prefs/BackupDatabaseActivity.java
+++ b/notepad-app-level-11/src/main/java/org/routine_work/notepad/prefs/BackupDatabaseActivity.java
@@ -23,24 +23,41 @@
2323 */
2424 package org.routine_work.notepad.prefs;
2525
26+import android.Manifest;
2627 import android.app.Activity;
2728 import android.content.Intent;
29+import android.content.pm.PackageManager;
30+import android.os.Build;
2831 import android.os.Bundle;
29-import android.util.Log;
3032 import android.view.View;
3133 import android.view.View.OnClickListener;
3234 import android.widget.Button;
35+import android.widget.TextView;
3336 import org.routine_work.notepad.R;
37+import org.routine_work.utils.Log;
3438
3539 public class BackupDatabaseActivity extends Activity
36- implements OnClickListener, BackupConstants
37-{
40+ implements OnClickListener, BackupConstants {
3841
3942 private static final String LOG_TAG = "simple-notepad";
43+ private final int REQUEST_EXTERNAL_STORAGE_PERMISSION = 1001;
4044
4145 @Override
42- protected void onCreate(Bundle savedInstanceState)
43- {
46+ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
47+ Log.v(LOG_TAG, "Hello");
48+
49+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
50+ if (requestCode == REQUEST_EXTERNAL_STORAGE_PERMISSION) {
51+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
52+ enableBackupFunction();
53+ }
54+ }
55+
56+ Log.v(LOG_TAG, "Bye");
57+ }
58+
59+ @Override
60+ protected void onCreate(Bundle savedInstanceState) {
4461 Log.v(LOG_TAG, "Hello");
4562 setTheme(NotepadPreferenceUtils.getTheme(this));
4663 super.onCreate(savedInstanceState);
@@ -48,17 +65,38 @@ public class BackupDatabaseActivity extends Activity
4865
4966 Button okButton = (Button) findViewById(R.id.ok_button);
5067 okButton.setOnClickListener(this);
68+ okButton.setEnabled(false);
5169 Button cancelButton = (Button) findViewById(R.id.cancel_button);
5270 cancelButton.setOnClickListener(this);
71+
72+ if (Build.VERSION.SDK_INT >= 23) { // Android 6.0 or later
73+ if (PermissionUtils.hasExternalStoragePermission(this) == false) {
74+ this.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_EXTERNAL_STORAGE_PERMISSION);
75+ }
76+ }
77+ Log.v(LOG_TAG, "Bye");
78+ }
79+
80+ @Override
81+ protected void onResume() {
82+ super.onResume();
83+ Log.v(LOG_TAG, "Hello");
84+
85+ if (PermissionUtils.hasExternalStoragePermission(this)) { // Android 6.0 or later
86+ Log.v(LOG_TAG, "hasWriteStoragePermission() : true");
87+ enableBackupFunction();
88+ } else {
89+ Log.v(LOG_TAG, "hasWriteStoragePermission() : false");
90+ disableBackupFunction();
91+ }
92+
5393 Log.v(LOG_TAG, "Bye");
5494 }
5595
5696 @Override
57- public void onClick(View view)
58- {
97+ public void onClick(View view) {
5998 int id = view.getId();
60- switch (id)
61- {
99+ switch (id) {
62100 case R.id.ok_button:
63101 startBackupDatabaseService();
64102 setResult(RESULT_OK);
@@ -71,13 +109,31 @@ public class BackupDatabaseActivity extends Activity
71109 }
72110 }
73111
74- private void startBackupDatabaseService()
75- {
112+ private void enableBackupFunction() {
113+ Button okButton = (Button) findViewById(R.id.ok_button);
114+ okButton.setEnabled(true);
115+
116+ View rationaleView = findViewById(R.id.request_permission_rationale_external_storage_view);
117+ rationaleView.setVisibility(View.GONE);
118+ }
119+
120+ private void disableBackupFunction() {
121+ Button okButton = (Button) findViewById(R.id.ok_button);
122+ okButton.setEnabled(false);
123+
124+ View rationaleView = findViewById(R.id.request_permission_rationale_external_storage_view);
125+ rationaleView.setVisibility(View.VISIBLE);
126+ }
127+
128+ private void startBackupDatabaseService() {
76129 Log.v(LOG_TAG, "Hello");
77130
78- Intent backDatabaseIntent = new Intent(this, BackupDatabaseService.class);
79- startService(backDatabaseIntent);
131+ if (PermissionUtils.hasExternalStoragePermission(this)) { // re check
132+ Intent backDatabaseIntent = new Intent(this, BackupDatabaseService.class);
133+ startService(backDatabaseIntent);
134+ }
80135
81136 Log.v(LOG_TAG, "Bye");
82137 }
138+
83139 }
--- /dev/null
+++ b/notepad-app-level-11/src/main/java/org/routine_work/notepad/prefs/PermissionUtils.java
@@ -0,0 +1,58 @@
1+/*
2+ * The MIT License
3+ *
4+ * Copyright 2016 Masahiko, SAWAI <masahiko.sawai@gmail.com>.
5+ *
6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7+ * of this software and associated documentation files (the "Software"), to deal
8+ * in the Software without restriction, including without limitation the rights
9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+ * copies of the Software, and to permit persons to whom the Software is
11+ * furnished to do so, subject to the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be included in
14+ * all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+ * THE SOFTWARE.
23+ */
24+package org.routine_work.notepad.prefs;
25+
26+import android.Manifest;
27+import android.content.Context;
28+import android.content.pm.PackageManager;
29+import android.os.Build;
30+import org.routine_work.utils.Log;
31+
32+public class PermissionUtils {
33+
34+ private static final String LOG_TAG = "simple-notepad";
35+
36+ public static boolean hasExternalStoragePermission(Context context) {
37+ return hasPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE);
38+ }
39+
40+ public static boolean hasPermission(Context context, String permission) {
41+ boolean result;
42+ Log.v(LOG_TAG, "Hello");
43+
44+ if (Build.VERSION.SDK_INT >= 23) { // Android 6.0 or later
45+ if (context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED) {
46+ result = true;
47+ } else {
48+ result = false;
49+ }
50+ } else {
51+ result = true;
52+ }
53+
54+ Log.v(LOG_TAG, "Bye");
55+ return result;
56+ }
57+
58+}
--- a/notepad-app-level-11/src/main/java/org/routine_work/notepad/prefs/PickBackupFileActivity.java
+++ b/notepad-app-level-11/src/main/java/org/routine_work/notepad/prefs/PickBackupFileActivity.java
@@ -23,10 +23,13 @@
2323 */
2424 package org.routine_work.notepad.prefs;
2525
26+import android.Manifest;
2627 import android.app.Activity;
2728 import android.app.ListActivity;
2829 import android.content.Intent;
30+import android.content.pm.PackageManager;
2931 import android.net.Uri;
32+import android.os.Build;
3033 import android.os.Bundle;
3134 import android.os.Environment;
3235 import android.view.View;
@@ -47,28 +50,37 @@ import org.routine_work.utils.Log;
4750 * @author Masahiko, SAWAI <masahiko.sawai@gmail.com>
4851 */
4952 public class PickBackupFileActivity extends ListActivity
50- implements AdapterView.OnItemClickListener, NotepadConstants, BackupConstants
51-{
53+ implements AdapterView.OnItemClickListener, NotepadConstants, BackupConstants {
5254
5355 private static final String LOG_TAG = "simple-notepad";
56+ private static final int REQUEST_EXTERNAL_STORAGE_PERMISSION = 1001;
5457 private static final String MAPPING_KEY_FILE_PATH = "FILE";
5558 private static final String MAPPING_KEY_FILE_NAME = "BASENAME";
56- private static final String[] MAPPING_FROM = new String[]
57- {
58- MAPPING_KEY_FILE_NAME,
59- };
60- private static final int[] MAPPING_TO = new int[]
61- {
62- android.R.id.text1,
63- };
59+ private static final String[] MAPPING_FROM = new String[]{
60+ MAPPING_KEY_FILE_NAME,};
61+ private static final int[] MAPPING_TO = new int[]{
62+ android.R.id.text1,};
6463 // instances
6564 private final FilenameFilter backupFilenameFilter = new BackupFilenameFilter();
6665 private final List<Map<String, String>> backupFileDataList = new ArrayList<Map<String, String>>();
6766 private SimpleAdapter simpleAdapter;
6867
6968 @Override
70- public void onCreate(Bundle savedInstanceState)
71- {
69+ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
70+ Log.v(LOG_TAG, "Hello");
71+
72+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
73+ if (requestCode == REQUEST_EXTERNAL_STORAGE_PERMISSION) {
74+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
75+ enableRestoreFunction();
76+ }
77+ }
78+
79+ Log.v(LOG_TAG, "Bye");
80+ }
81+
82+ @Override
83+ public void onCreate(Bundle savedInstanceState) {
7284 Log.v(LOG_TAG, "Hello");
7385
7486 setTheme(NotepadPreferenceUtils.getTheme(this));
@@ -78,37 +90,47 @@ public class PickBackupFileActivity extends ListActivity
7890 // initialize title
7991 Intent intent = getIntent();
8092 String title = intent.getStringExtra(Intent.EXTRA_TITLE);
81- if (title != null)
82- {
93+ if (title != null) {
8394 setTitle(title);
8495 }
8596
8697 // initialize list adapter
8798 simpleAdapter = new SimpleAdapter(this, backupFileDataList,
88- android.R.layout.simple_list_item_1,
89- MAPPING_FROM, MAPPING_TO);
99+ android.R.layout.simple_list_item_1,
100+ MAPPING_FROM, MAPPING_TO);
90101 setListAdapter(simpleAdapter);
91102
92103 ListView listView = getListView();
93104 listView.setOnItemClickListener(this);
94105
106+ if (Build.VERSION.SDK_INT >= 23) { // Android 6.0 or later
107+ if (PermissionUtils.hasExternalStoragePermission(this) == false) {
108+ this.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_EXTERNAL_STORAGE_PERMISSION);
109+ }
110+ }
111+
95112 Log.v(LOG_TAG, "Bye");
96113 }
97114
98115 @Override
99- protected void onResume()
100- {
116+ protected void onResume() {
101117 Log.v(LOG_TAG, "Hello");
102118 super.onResume();
103119
104120 updateListData();
121+ if (PermissionUtils.hasExternalStoragePermission(this)) { // Android 6.0 or later
122+ Log.v(LOG_TAG, "hasReadStoragePermission() : true");
123+ enableRestoreFunction();
124+ } else {
125+ Log.v(LOG_TAG, "hasReadStoragePermission() : false");
126+ disableRestoreFunction();
127+ }
105128
106129 Log.v(LOG_TAG, "Bye");
107130 }
108131
109132 @Override
110- public void onItemClick(AdapterView<?> av, View view, int position, long id)
111- {
133+ public void onItemClick(AdapterView<?> av, View view, int position, long id) {
112134 Log.v(LOG_TAG, "Hello");
113135
114136 Map<String, String> backupFileData = backupFileDataList.get(position);
@@ -125,25 +147,20 @@ public class PickBackupFileActivity extends ListActivity
125147 Log.v(LOG_TAG, "Bye");
126148 }
127149
128- private synchronized void updateListData()
129- {
150+ private synchronized void updateListData() {
130151 Log.v(LOG_TAG, "Hello");
131152
132153 String externalStorageState = Environment.getExternalStorageState();
133- if (externalStorageState.equals(Environment.MEDIA_MOUNTED))
134- {
154+ if (externalStorageState.equals(Environment.MEDIA_MOUNTED)) {
135155 File backupDirPath = Environment.getExternalStorageDirectory();
136156 backupDirPath = new File(backupDirPath, BACKUP_DIR_NAME);
137157 Log.d(LOG_TAG, "backupDirPath => " + backupDirPath);
138158
139- if (backupDirPath.exists() && backupDirPath.canRead())
140- {
159+ if (backupDirPath.exists() && backupDirPath.canRead()) {
141160 File[] listFiles = backupDirPath.listFiles(backupFilenameFilter);
142- if (listFiles != null)
143- {
161+ if (listFiles != null) {
144162 backupFileDataList.clear();
145- for (File file : listFiles)
146- {
163+ for (File file : listFiles) {
147164 Map<String, String> backupFileData = new HashMap<String, String>();
148165 backupFileData.put(MAPPING_KEY_FILE_PATH, file.getAbsolutePath());
149166 backupFileData.put(MAPPING_KEY_FILE_NAME, file.getName());
@@ -154,26 +171,31 @@ public class PickBackupFileActivity extends ListActivity
154171 }
155172 }
156173
157- if (simpleAdapter != null)
158- {
174+ if (simpleAdapter != null) {
159175 simpleAdapter.notifyDataSetChanged();
160176 }
161177
162178 Log.v(LOG_TAG, "Bye");
163179 }
164180
165- class BackupFilenameFilter implements FilenameFilter
166- {
181+ private void disableRestoreFunction() {
182+ View rationaleView = findViewById(R.id.request_permission_rationale_external_storage_view);
183+ rationaleView.setVisibility(View.VISIBLE);
184+ }
185+
186+ private void enableRestoreFunction() {
187+ View rationaleView = findViewById(R.id.request_permission_rationale_external_storage_view);
188+ rationaleView.setVisibility(View.GONE);
189+ }
190+
191+ class BackupFilenameFilter implements FilenameFilter {
167192
168- public boolean accept(File dir, String name)
169- {
193+ public boolean accept(File dir, String name) {
170194 boolean result = false;
171- if (name.endsWith(BACKUP_FILE_SUFFIX))
172- {
195+ if (name.endsWith(BACKUP_FILE_SUFFIX)) {
173196 String basename = name.substring(0, name.length() - BACKUP_FILE_SUFFIX.length());
174197 Log.d(LOG_TAG, "basename => " + basename);
175- if (basename.length() >= BACKUP_FILE_DATE_FORMAT.length())
176- {
198+ if (basename.length() >= BACKUP_FILE_DATE_FORMAT.length()) {
177199 result = true;
178200 }
179201 }
--- a/notepad-app-level-11/src/main/java/org/routine_work/notepad/prefs/RestoreDatabaseActivity.java
+++ b/notepad-app-level-11/src/main/java/org/routine_work/notepad/prefs/RestoreDatabaseActivity.java
@@ -23,15 +23,18 @@
2323 */
2424 package org.routine_work.notepad.prefs;
2525
26+import android.Manifest;
2627 import android.app.Activity;
2728 import android.content.Intent;
2829 import android.net.Uri;
30+import android.os.Build;
2931 import android.os.Bundle;
3032 import android.os.Environment;
3133 import android.util.Log;
3234 import android.view.View;
3335 import android.view.View.OnClickListener;
3436 import android.widget.Button;
37+import android.widget.TextView;
3538 import android.widget.Toast;
3639 import java.io.File;
3740 import java.io.FileInputStream;
@@ -42,8 +45,7 @@ import org.routine_work.notepad.NotepadActivity;
4245 import org.routine_work.notepad.R;
4346 import org.routine_work.notepad.provider.NoteStore;
4447
45-public class RestoreDatabaseActivity extends Activity implements OnClickListener
46-{
48+public class RestoreDatabaseActivity extends Activity implements OnClickListener {
4749
4850 private static final String LOG_TAG = "simple-notepad";
4951 private static final String SAVE_KEY_BACKUP_FILE_PATH = "backupFilePath";
@@ -51,11 +53,9 @@ public class RestoreDatabaseActivity extends Activity implements OnClickListener
5153 private static final int REUQEST_CODE_PICK_BACKUP_FILE = 1;
5254
5355 @Override
54- public void onClick(View view)
55- {
56+ public void onClick(View view) {
5657 int id = view.getId();
57- switch (id)
58- {
58+ switch (id) {
5959 case R.id.ok_button:
6060 restoreDatabaseFile();
6161 NotepadActivity.quitApplication(this);
@@ -68,29 +68,23 @@ public class RestoreDatabaseActivity extends Activity implements OnClickListener
6868 }
6969
7070 @Override
71- protected void onCreate(Bundle savedInstanceState)
72- {
71+ protected void onCreate(Bundle savedInstanceState) {
7372 setTheme(NotepadPreferenceUtils.getTheme(this));
7473 super.onCreate(savedInstanceState);
7574 setContentView(R.layout.restore_database_activity);
7675
77- if (savedInstanceState != null)
78- {
76+ if (savedInstanceState != null) {
7977 backupFilePath = savedInstanceState.getString(SAVE_KEY_BACKUP_FILE_PATH);
80- }
81- else
82- {
78+ } else {
8379 Intent intent = getIntent();
8480 Uri data = intent.getData();
85- if (data != null)
86- {
81+ if (data != null) {
8782 backupFilePath = data.getPath();
8883 }
8984 }
9085 Log.d(LOG_TAG, "backupFilePath => " + backupFilePath);
9186
92- if (backupFilePath == null)
93- {
87+ if (backupFilePath == null) {
9488 Intent pickBackupFileIntent = new Intent(this, PickBackupFileActivity.class);
9589 startActivityForResult(pickBackupFileIntent, REUQEST_CODE_PICK_BACKUP_FILE);
9690 }
@@ -104,20 +98,26 @@ public class RestoreDatabaseActivity extends Activity implements OnClickListener
10498 }
10599
106100 @Override
107- protected void onActivityResult(int requestCode, int resultCode, Intent data)
108- {
109- switch (requestCode)
110- {
101+ protected void onResume() {
102+ super.onResume(); //To change body of generated methods, choose Tools | Templates.
103+ if (PermissionUtils.hasExternalStoragePermission(this)) { // Android 6.0 or later
104+ enableRestoreFunction();
105+ } else {
106+ disableRestoreFunction();
107+ }
108+ }
109+
110+ @Override
111+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
112+ switch (requestCode) {
111113 case REUQEST_CODE_PICK_BACKUP_FILE:
112- if (resultCode == RESULT_OK)
113- {
114+ if (resultCode == RESULT_OK) {
114115 Uri uri = data.getData();
115116 backupFilePath = uri.getPath();
116117 }
117118 Log.d(LOG_TAG, "backupFilePath => " + backupFilePath);
118119
119- if (backupFilePath == null)
120- {
120+ if (backupFilePath == null) {
121121 setResult(RESULT_CANCELED);
122122 finish();
123123 }
@@ -128,46 +128,56 @@ public class RestoreDatabaseActivity extends Activity implements OnClickListener
128128 }
129129
130130 @Override
131- protected void onSaveInstanceState(Bundle outState)
132- {
131+ protected void onSaveInstanceState(Bundle outState) {
133132 super.onSaveInstanceState(outState);
134133 outState.putString(SAVE_KEY_BACKUP_FILE_PATH, backupFilePath);
135134 }
136135
137- private void restoreDatabaseFile()
138- {
136+ private void restoreDatabaseFile() {
139137 Log.d(LOG_TAG, "backupFilePath => " + backupFilePath);
140- if (backupFilePath == null)
141- {
138+ if (backupFilePath == null) {
142139 Log.e(LOG_TAG, "backup file path is null, the restore was canceled.");
143140 return;
144141 }
145142
146143 String externalStorageState = Environment.getExternalStorageState();
147- if (Environment.MEDIA_MOUNTED.equals(externalStorageState))
148- {
144+ if (Environment.MEDIA_MOUNTED.equals(externalStorageState)) {
149145 File databaseFilePath = NoteStore.getNoteDatabasePath(this);
150146 Log.d(LOG_TAG, "databaseFilePath => " + databaseFilePath);
151147
152- try
153- {
148+ try {
154149 Log.i(LOG_TAG, "Restore database " + backupFilePath + " to " + databaseFilePath);
155150 FileChannel inputChannel = new FileInputStream(backupFilePath).getChannel();
156151 FileChannel outputChannel = new FileOutputStream(databaseFilePath).getChannel();
157152 inputChannel.transferTo(0, inputChannel.size(), outputChannel);
158153 inputChannel.close();
159154 outputChannel.close();
160- }
161- catch (IOException ex)
162- {
155+ } catch (IOException ex) {
163156 Log.e(LOG_TAG, "The database file copying is failed.", ex);
164157 }
165- }
166- else
167- {
158+ } else {
168159 String message = "The external storage is not mounted.";
169160 Log.e(LOG_TAG, message + "externalStorageState => " + externalStorageState);
170161 Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
171162 }
172163 }
164+
165+ private void disableRestoreFunction() {
166+ View rationaleView = findViewById(R.id.request_permission_rationale_external_storage_view);
167+ rationaleView.setVisibility(View.VISIBLE);
168+
169+ Button okButton = (Button) findViewById(R.id.ok_button);
170+ okButton.setEnabled(false);
171+
172+ }
173+
174+ private void enableRestoreFunction() {
175+ // remove permission rationale
176+ View rationaleView = findViewById(R.id.request_permission_rationale_external_storage_view);
177+ rationaleView.setVisibility(View.GONE);
178+
179+ // enable ok button
180+ Button okButton = (Button) findViewById(R.id.ok_button);
181+ okButton.setEnabled(true);
182+ }
173183 }
--- a/notepad-app-level-11/src/main/res/layout/backup_database_activity.xml
+++ b/notepad-app-level-11/src/main/res/layout/backup_database_activity.xml
@@ -6,15 +6,24 @@
66 android:layout_height="fill_parent"
77 android:orientation="vertical"
88 >
9- <TextView
9+ <LinearLayout
10+ android:orientation="vertical"
1011 android:layout_width="fill_parent"
1112 android:layout_height="wrap_content"
1213 android:layout_weight="1"
1314 android:padding="4dip"
14- android:text="@string/backup_data_confirm_message"
15- android:textColor="?android:attr/textColorPrimary"
16- android:textSize="18sp"
17- />
15+ >
16+ <TextView
17+ android:layout_width="fill_parent"
18+ android:layout_height="wrap_content"
19+ android:layout_weight="0"
20+ android:padding="4dip"
21+ android:text="@string/backup_data_confirm_message"
22+ android:textColor="?android:attr/textColorPrimary"
23+ android:textSize="18sp"
24+ />
25+ <include layout="@layout/request_permission_rationale_external_storage" />
26+ </LinearLayout>
1827
1928 <View style="@style/hline" />
2029
--- a/notepad-app-level-11/src/main/res/layout/pick_backup_file_activity.xml
+++ b/notepad-app-level-11/src/main/res/layout/pick_backup_file_activity.xml
@@ -1,8 +1,7 @@
11 <?xml version="1.0" encoding="utf-8"?>
22 <FrameLayout
33 xmlns:android="http://schemas.android.com/apk/res/android"
4- android:layout_width="fill_parent"
5- android:layout_height="fill_parent"
4+ style="@style/body"
65 >
76 <ListView
87 android:id="@android:id/list"
@@ -18,4 +17,10 @@
1817 android:layout_gravity="center"
1918 android:text="@string/no_backup_file"
2019 />
20+ <FrameLayout
21+ android:layout_width="fill_parent"
22+ android:layout_height="fill_parent"
23+ >
24+ <include layout="@layout/request_permission_rationale_external_storage" />
25+ </FrameLayout>
2126 </FrameLayout>
\ No newline at end of file
--- a/notepad-app-level-11/src/main/res/layout/pick_note_activity.xml
+++ b/notepad-app-level-11/src/main/res/layout/pick_note_activity.xml
@@ -2,8 +2,6 @@
22 <FrameLayout
33 xmlns:android="http://schemas.android.com/apk/res/android"
44 style="@style/body"
5- android:layout_width="fill_parent"
6- android:layout_height="fill_parent"
75 >
86
97 <include layout="@layout/note_list" />
--- /dev/null
+++ b/notepad-app-level-11/src/main/res/layout/request_permission_rationale_external_storage.xml
@@ -0,0 +1,16 @@
1+<?xml version="1.0" encoding="utf-8"?>
2+<FrameLayout
3+ xmlns:android="http://schemas.android.com/apk/res/android"
4+ android:id="@+id/request_permission_rationale_external_storage_view"
5+ android:layout_width="wrap_content"
6+ android:layout_height="wrap_content"
7+>
8+ <TextView
9+ android:layout_width="wrap_content"
10+ android:layout_height="wrap_content"
11+ android:padding="4dip"
12+ android:text="@string/request_permission_rationale_external_storage"
13+ android:textColor="?android:attr/textColorPrimary"
14+ android:textSize="18sp"
15+ />
16+</FrameLayout>
\ No newline at end of file
--- a/notepad-app-level-11/src/main/res/layout/restore_database_activity.xml
+++ b/notepad-app-level-11/src/main/res/layout/restore_database_activity.xml
@@ -6,15 +6,24 @@
66 android:layout_height="fill_parent"
77 android:orientation="vertical"
88 >
9- <TextView
9+ <LinearLayout
10+ android:orientation="vertical"
1011 android:layout_width="fill_parent"
1112 android:layout_height="wrap_content"
1213 android:layout_weight="1"
1314 android:padding="4dip"
14- android:text="@string/restore_data_confirm_message"
15- android:textColor="?android:attr/textColorPrimary"
16- android:textSize="18sp"
17- />
15+ >
16+ <TextView
17+ android:layout_width="fill_parent"
18+ android:layout_height="wrap_content"
19+ android:layout_weight="0"
20+ android:padding="4dip"
21+ android:text="@string/restore_data_confirm_message"
22+ android:textColor="?android:attr/textColorPrimary"
23+ android:textSize="18sp"
24+ />
25+ <include layout="@layout/request_permission_rationale_external_storage" />
26+ </LinearLayout>
1827
1928 <View style="@style/hline" />
2029
--- a/notepad-app-level-11/src/main/res/values-ja/strings_preferences.xml
+++ b/notepad-app-level-11/src/main/res/values-ja/strings_preferences.xml
@@ -100,6 +100,7 @@
100100 <string name="backup_data_confirm_message">すべてのノートとテンプレートが外部ストレージにバックアップされます。</string>
101101 <string name="backup_data_completed_message">ノートとテンプレートのバックアップが完了しました。</string>
102102 <string name="external_storage_not_mountted">外部ストレージが接続されていません。</string>
103+ <string name="request_permission_rationale_external_storage">バックアップ作成と復元のために、外部ストレージへの読み書きに対して許可が必要です。</string>
103104 <!-- Restore Notes -->
104105 <string name="restore_data">データを復元</string>
105106 <string name="restore_data_title">データを復元</string>
--- a/notepad-app-level-11/src/main/res/values/strings_preference.xml
+++ b/notepad-app-level-11/src/main/res/values/strings_preference.xml
@@ -100,6 +100,7 @@
100100 <string name="backup_data_confirm_message">All notes and templates will be backed up to the external storage.</string>
101101 <string name="backup_data_completed_message">All notes and templates were backed up.</string>
102102 <string name="external_storage_not_mountted">The external storage is not mounted.</string>
103+ <string name="request_permission_rationale_external_storage">To back up and restore, access permission to the external storage is required.</string>
103104 <!-- Restore Data -->
104105 <string name="restore_data">Restore data</string>
105106 <string name="restore_data_title">Restore data</string>