Skip to content

Commit 9bbd203

Browse files
committed
Add a Settings activity
This includes a rudimentary system to directly copy Kolibri content from a zip file. For it to work correctly will require additional support code in kolibri-explore-plugin. endlessm/endless-key-content-private#102
1 parent 361241f commit 9bbd203

6 files changed

Lines changed: 233 additions & 0 deletions

File tree

app/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,10 @@ dependencies {
227227
implementation("androidx.annotation:annotation:1.7.0")
228228
implementation("androidx.core:core:1.10.1")
229229

230+
implementation("androidx.appcompat:appcompat:1.6.1")
231+
implementation("com.google.android.material:material:1.9.0")
232+
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
233+
230234
// Firebase Analytics and Crashlytics
231235
implementation(platform("com.google.firebase:firebase-bom:32.3.1"))
232236
implementation("com.google.firebase:firebase-analytics")

app/src/main/AndroidManifest.xml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
<category android:name="android.intent.category.LAUNCHER" />
4343
</intent-filter>
4444

45+
<meta-data android:name="android.app.shortcuts"
46+
android:resource="@xml/shortcuts" />
4547
<meta-data android:name="WindowManagerPreference:FreeformWindowSize"
4648
android:value="maximize" />
4749
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation"
@@ -51,6 +53,23 @@
5153

5254
</activity>
5355

56+
<activity
57+
android:name=".SettingsActivity"
58+
android:theme="@android:style/Theme.Material.Light"
59+
android:exported="true"
60+
android:parentActivityName="org.endlessos.key.KolibriActivity"
61+
>
62+
63+
<intent-filter>
64+
<action android:name="android.intent.action.MAIN" />
65+
</intent-filter>
66+
67+
<meta-data
68+
android:name="android.support.PARENT_ACTIVITY"
69+
android:value="org.endlessos.key.KolibriActivity" />
70+
71+
</activity>
72+
5473
<service android:name=".KolibriService"
5574
android:exported="false"
5675
android:process=":kolibri" />
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package org.endlessos.key;
2+
3+
import android.app.Activity;
4+
import android.content.Intent;
5+
import android.net.Uri;
6+
import android.os.Bundle;
7+
import android.util.Log;
8+
import android.view.View;
9+
import android.widget.Button;
10+
import android.widget.Toolbar;
11+
12+
import java.io.BufferedInputStream;
13+
import java.io.File;
14+
import java.io.FileNotFoundException;
15+
import java.io.FileOutputStream;
16+
import java.io.IOException;
17+
import java.io.InputStream;
18+
import java.util.zip.ZipEntry;
19+
import java.util.zip.ZipException;
20+
import java.util.zip.ZipInputStream;
21+
22+
public class SettingsActivity extends Activity {
23+
// TODO: Add a way back to the main activity.
24+
// TODO: Restart the Kolibri service if it is running.
25+
// TODO: Show progress while importing.
26+
// TODO: Disable the import button while importing.
27+
// TODO: Display helpful information after importing.
28+
29+
private static final String TAG = Constants.TAG;
30+
31+
private static final int CHOOSE_FILE_RESULT_CODE = 8778;
32+
33+
@Override
34+
protected void onCreate(Bundle savedInstanceState) {
35+
super.onCreate(savedInstanceState);
36+
setContentView(R.layout.activity_settings);
37+
38+
getActionBar().setTitle("Endless Key Settings");
39+
40+
final Button importContentButton = findViewById(R.id.importContentButton);
41+
importContentButton.setOnClickListener(
42+
new View.OnClickListener() {
43+
44+
@Override
45+
public void onClick(View view) {
46+
Log.i("importContent", "onClick");
47+
startImportContent();
48+
}
49+
}
50+
);
51+
}
52+
53+
private void startImportContent() {
54+
Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT);
55+
chooseFile.addCategory(Intent.CATEGORY_OPENABLE);
56+
chooseFile.setType("application/zip");
57+
startActivityForResult(
58+
Intent.createChooser(chooseFile, "Choose a file"),
59+
CHOOSE_FILE_RESULT_CODE
60+
);
61+
}
62+
63+
@Override
64+
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
65+
super.onActivityResult(requestCode, resultCode, data);
66+
67+
if (requestCode != CHOOSE_FILE_RESULT_CODE) {
68+
return;
69+
}
70+
71+
if (resultCode != Activity.RESULT_OK) {
72+
return;
73+
}
74+
75+
try {
76+
copyKolibriContent(
77+
data.getData(),
78+
KolibriUtils.getKolibriHome(getBaseContext())
79+
);
80+
} catch (IOException e) {
81+
e.printStackTrace();
82+
}
83+
}
84+
85+
protected void copyKolibriContent(Uri sourceContent, File outputDirectory) throws IOException {
86+
InputStream fileInput;
87+
88+
fileInput = getContentResolver().openInputStream(sourceContent);
89+
90+
ZipInputStream zipInput = new ZipInputStream(new BufferedInputStream(fileInput));
91+
ZipEntry zipEntry = null;
92+
byte[] buffer = new byte[1024];
93+
94+
while (true) {
95+
String fileName;
96+
File outputFile;
97+
98+
zipEntry = zipInput.getNextEntry();
99+
100+
if (zipEntry == null) {
101+
break;
102+
}
103+
104+
fileName = zipEntry.getName();
105+
106+
if (!fileName.startsWith("content/")) {
107+
Log.d(TAG, "Content file has wrong parent directory: " + fileName);
108+
break;
109+
}
110+
111+
if (fileName.equals("content/manifest.json")) {
112+
Long timeSeconds = System.currentTimeMillis() / 1000;
113+
fileName = "content/manifest."+timeSeconds+".json";
114+
}
115+
116+
outputFile = new File(outputDirectory, fileName);
117+
118+
if (zipEntry.isDirectory()) {
119+
try {
120+
outputFile.mkdirs();
121+
} catch (SecurityException error) {
122+
error.printStackTrace();
123+
}
124+
} else {
125+
int count;
126+
FileOutputStream fileOutput;
127+
128+
fileOutput = new FileOutputStream(outputFile);
129+
130+
while (true) {
131+
count = zipInput.read(buffer);
132+
133+
if (count == -1) {
134+
break;
135+
}
136+
137+
fileOutput.write(buffer, 0, count);
138+
}
139+
140+
fileOutput.close();
141+
zipInput.closeEntry();
142+
}
143+
}
144+
}
145+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
xmlns:tools="http://schemas.android.com/tools"
5+
android:layout_width="match_parent"
6+
android:layout_height="match_parent"
7+
tools:context=".SettingsActivity">
8+
9+
<androidx.constraintlayout.widget.ConstraintLayout
10+
android:layout_width="0dp"
11+
android:layout_height="413dp"
12+
app:layout_constraintEnd_toEndOf="parent"
13+
app:layout_constraintStart_toStartOf="parent"
14+
app:layout_constraintTop_toTopOf="parent">
15+
16+
<Button
17+
android:id="@+id/importContentButton"
18+
android:layout_width="wrap_content"
19+
android:layout_height="wrap_content"
20+
android:text="Import content zip"
21+
app:layout_constraintBottom_toBottomOf="parent"
22+
app:layout_constraintEnd_toEndOf="parent"
23+
app:layout_constraintStart_toStartOf="parent"
24+
app:layout_constraintTop_toTopOf="parent" />
25+
26+
<ProgressBar
27+
android:id="@+id/importContentProgress"
28+
style="?android:attr/progressBarStyleHorizontal"
29+
android:layout_width="0dp"
30+
android:layout_height="wrap_content"
31+
app:layout_constraintBottom_toBottomOf="parent"
32+
app:layout_constraintEnd_toEndOf="parent"
33+
app:layout_constraintStart_toStartOf="parent" />
34+
</androidx.constraintlayout.widget.ConstraintLayout>
35+
36+
<ScrollView
37+
android:layout_width="0dp"
38+
android:layout_height="413dp"
39+
app:layout_constraintBottom_toBottomOf="parent"
40+
app:layout_constraintEnd_toEndOf="parent"
41+
app:layout_constraintStart_toStartOf="parent"
42+
app:layout_constraintTop_toBottomOf="@+id/topLayout">
43+
44+
<TextView
45+
android:id="@+id/outputTextView"
46+
android:layout_width="match_parent"
47+
android:layout_height="wrap_content" />
48+
</ScrollView>
49+
50+
</androidx.constraintlayout.widget.ConstraintLayout>

app/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@
55
You need to update the Android System Webview component to use Endless Key.
66
</string>
77
<string name="webview_check_update">Update</string>
8+
<string name="settings_short_label">Settings</string>
9+
<string name="settings_long_label">Settings</string>
810
</resources>

app/src/main/res/xml/shortcuts.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
2+
<shortcut
3+
android:shortcutId="settings"
4+
android:enabled="true"
5+
android:icon="@android:drawable/ic_menu_preferences"
6+
android:shortcutShortLabel="@string/settings_short_label"
7+
android:shortcutLongLabel="@string/settings_long_label">
8+
<intent
9+
android:action="android.intent.action.MAIN"
10+
android:targetPackage="org.endlessos.testapp"
11+
android:targetClass="org.endlessos.testapp.SettingsActivity" />
12+
</shortcut>
13+
</shortcuts>

0 commit comments

Comments
 (0)