mirror of
https://gitlab.com/octtspacc/browserocto
synced 2025-06-05 21:49:19 +02:00
First commit, basic working app for Android > 7 (bad UX on lower versions)
This commit is contained in:
24
app/build.gradle
Normal file
24
app/build.gradle
Normal file
@ -0,0 +1,24 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "21.1.0"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "org.eu.octt.browserocto"
|
||||
minSdkVersion 1
|
||||
targetSdkVersion 29
|
||||
versionCode 1
|
||||
versionName "1.0.0"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
//compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
}
|
17
app/proguard-rules.pro
vendored
Normal file
17
app/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in C:\tools\adt-bundle-windows-x86_64-20131030\sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
32
app/src/main/AndroidManifest.xml
Normal file
32
app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.eu.octt.browserocto">
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme"
|
||||
android:resizeableActivity="true">
|
||||
<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"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.CREATE_SHORTCUT"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".WebWindowActivity"
|
||||
android:label="@string/app_name"
|
||||
android:exported="true">
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
134
app/src/main/java/org/eu/octt/browserocto/MainActivity.java
Normal file
134
app/src/main/java/org/eu/octt/browserocto/MainActivity.java
Normal file
@ -0,0 +1,134 @@
|
||||
package org.eu.octt.browserocto;
|
||||
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.os.*;
|
||||
import android.widget.*;
|
||||
import android.view.View.*;
|
||||
import android.view.*;
|
||||
import android.net.*;
|
||||
import android.content.pm.*;
|
||||
import android.graphics.drawable.*;
|
||||
|
||||
public class MainActivity extends Activity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main);
|
||||
|
||||
final LinearLayout LayMain = findViewById(R.id.LayMain);
|
||||
final EditText EditUrl = findViewById(R.id.EditUrl);
|
||||
final Button BtnOpen = findViewById(R.id.BtnOpen);
|
||||
final Button BtnShortcut = findViewById(R.id.BtnShortcut);
|
||||
final Switch SwitchCache = findViewById(R.id.SwitchCache);
|
||||
|
||||
BtnOpen.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String Url = EditUrl.getText().toString();
|
||||
if (_Util.IsUrlValid(Url)) {
|
||||
startActivity(MakeIntBrowse(Url, SwitchCache.isChecked()));
|
||||
} else {
|
||||
_Util.ToastMsg("URL is invalid!", getApplicationContext());
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
BtnShortcut.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String Url = EditUrl.getText().toString();
|
||||
if (_Util.IsUrlValid(Url)) {
|
||||
ShowShortcutDial(Url);
|
||||
} else {
|
||||
_Util.ToastMsg("URL is invalid!", getApplicationContext());
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
private Intent MakeIntBrowse(String Url, Boolean Cache) {
|
||||
Intent IntBrowse = new Intent(getApplicationContext(), WebWindowActivity.class);
|
||||
// To get unlimited activities in general but only 1 per site, set only FLAG_ACTIVITY_NEW_DOCUMENT and put site URL in intent.setData
|
||||
// NOTE: This only gives a good UX on Android >= 7, for the lower versions we need to implement things differently
|
||||
IntBrowse
|
||||
.setAction(Intent.ACTION_OPEN_DOCUMENT)
|
||||
.setData(Uri.parse(Url))
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT /*| Intent.FLAG_ACTIVITY_MULTIPLE_TASK*/)
|
||||
.putExtra("Url", Url)
|
||||
.putExtra("Cache", Cache);
|
||||
return IntBrowse;
|
||||
};
|
||||
|
||||
private final void CreateShortcut(String Url, String Name) {
|
||||
// https://stackoverflow.com/a/51184905
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
ShortcutManager ShortMan = getApplicationContext().getSystemService(ShortcutManager.class);
|
||||
if (ShortMan != null) {
|
||||
if (ShortMan.isRequestPinShortcutSupported()) {
|
||||
ShortcutInfo shortcut = new ShortcutInfo.Builder(getApplicationContext(), Url)
|
||||
.setShortLabel(Name)
|
||||
//.setLongLabel("Open the Android Document")
|
||||
.setIcon(Icon.createWithResource(getApplicationContext(), R.drawable.ic_launcher)) // TODO Get site icon, or let user pick
|
||||
//.setIcon(IconFromUrlElseDefault(Url))
|
||||
.setIntent(MakeIntBrowse(Url, true))
|
||||
.build();
|
||||
ShortMan.requestPinShortcut(shortcut, null);
|
||||
} else {
|
||||
CreateShortcutFallback(Url, Name);
|
||||
};
|
||||
};
|
||||
} else {
|
||||
CreateShortcutFallback(Url, Name);
|
||||
};
|
||||
};
|
||||
|
||||
private final void CreateShortcutFallback(String Url, String Name) {
|
||||
Intent IntExt = new Intent();
|
||||
IntExt.putExtra(Intent.EXTRA_SHORTCUT_INTENT, MakeIntBrowse(Url, true));
|
||||
IntExt.putExtra(Intent.EXTRA_SHORTCUT_NAME, Name);
|
||||
IntExt.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(getApplicationContext(), R.drawable.ic_launcher));
|
||||
|
||||
IntExt.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
|
||||
//IntExt.putExtra("duplicate", false); //may it's already there so don't duplicate
|
||||
getApplicationContext().sendBroadcast(IntExt);
|
||||
};
|
||||
|
||||
|
||||
private void ShowShortcutDial(String Url) {
|
||||
final AlertDialog.Builder Dial = new AlertDialog.Builder(this);
|
||||
final String Url_ = Url;
|
||||
|
||||
final View v = getLayoutInflater().inflate(R.layout.dialmakeshortcut, null);
|
||||
Dial.setView(v);
|
||||
|
||||
final EditText EditName = v.findViewById(R.id.EditName);
|
||||
//final EditText EditIcon = v.findViewById(R.id.EditIcon);
|
||||
|
||||
Dial.setTitle("Create Home Shortcut");
|
||||
//Dial.setCancelable(false);
|
||||
|
||||
Dial.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface d, int w) {
|
||||
final String Name = EditName.getText().toString();
|
||||
//String IconUrl = EditIcon.getText().toString();
|
||||
if (!Name.equals("")) {
|
||||
CreateShortcut(Url_, Name);
|
||||
} else
|
||||
if (Name.equals("")) {
|
||||
_Util.ToastMsg("Name can't be empty!", getApplicationContext());
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
Dial.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface d, int w) {
|
||||
|
||||
};
|
||||
});
|
||||
|
||||
Dial.show();
|
||||
};
|
||||
};
|
@ -0,0 +1,34 @@
|
||||
package org.eu.octt.browserocto;
|
||||
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.os.*;
|
||||
import android.webkit.*;
|
||||
import android.widget.*;
|
||||
|
||||
public class WebWindowActivity extends Activity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.webwindow);
|
||||
|
||||
Bundle Extra = getIntent().getExtras();
|
||||
LinearLayout LayMain = findViewById(R.id.LayMain);
|
||||
|
||||
WebView Web0 = findViewById(R.id.Web0);
|
||||
Web0.setWebViewClient(new WebViewClient());
|
||||
Web0.getSettings().setJavaScriptEnabled(true);
|
||||
Web0.getSettings().setDomStorageEnabled(true);
|
||||
Web0.getSettings().setCacheMode(WhichCacheMode(Extra.getBoolean("Cache")));
|
||||
Web0.loadUrl(Extra.getString("Url"));
|
||||
|
||||
_Util.ToastMsg(Extra.getString("Url"), getApplicationContext());
|
||||
};
|
||||
|
||||
public int WhichCacheMode(boolean Opt) {
|
||||
if (Opt) {
|
||||
return WebSettings.LOAD_CACHE_ELSE_NETWORK;
|
||||
};
|
||||
return WebSettings.LOAD_NO_CACHE;
|
||||
};
|
||||
};
|
22
app/src/main/java/org/eu/octt/browserocto/_Util.java
Normal file
22
app/src/main/java/org/eu/octt/browserocto/_Util.java
Normal file
@ -0,0 +1,22 @@
|
||||
package org.eu.octt.browserocto;
|
||||
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.widget.*;
|
||||
|
||||
public class _Util extends Activity {
|
||||
public static void ToastMsg(String Msg, Context c) {
|
||||
Toast.makeText(c, Msg, Toast.LENGTH_SHORT).show();
|
||||
};
|
||||
|
||||
public static boolean IsUrlValid(String Url) {
|
||||
Url = Url.toLowerCase();
|
||||
if (
|
||||
(Url.startsWith("file://") || Url.startsWith("http://") || Url.startsWith("https://"))
|
||||
&& !(Url.equals("file://") || Url.equals("http://") || Url.equals("https://"))
|
||||
) {
|
||||
return true;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
};
|
BIN
app/src/main/res/drawable-hdpi/ic_launcher.png
Normal file
BIN
app/src/main/res/drawable-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
BIN
app/src/main/res/drawable-mdpi/ic_launcher.png
Normal file
BIN
app/src/main/res/drawable-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_launcher.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_launcher.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
57
app/src/main/res/layout/dialmakeshortcut.xml
Normal file
57
app/src/main/res/layout/dialmakeshortcut.xml
Normal file
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/LayMain"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp">
|
||||
|
||||
<!--
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Reset Name"
|
||||
android:padding="10dp"/>
|
||||
-->
|
||||
|
||||
<EditText
|
||||
android:layout_width="wrap_content"
|
||||
android:ems="10"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/EditName"
|
||||
android:padding="10dp"
|
||||
android:hint="Name..."/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!--
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp">
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Reset Icon URL"
|
||||
android:padding="10dp"/>
|
||||
|
||||
<EditText
|
||||
android:layout_width="wrap_content"
|
||||
android:ems="10"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/EditIcon"
|
||||
android:padding="10dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
-->
|
||||
|
||||
</LinearLayout>
|
49
app/src/main/res/layout/main.xml
Normal file
49
app/src/main/res/layout/main.xml
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/LayMain">
|
||||
|
||||
<EditText
|
||||
android:layout_width="match_parent"
|
||||
android:ems="10"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="URL..."
|
||||
android:text="https://"
|
||||
android:padding="10dp"
|
||||
android:id="@+id/EditUrl"/>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp">
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Open Now"
|
||||
android:padding="10dp"
|
||||
android:id="@+id/BtnOpen"/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Add Shortcut"
|
||||
android:padding="10dp"
|
||||
android:id="@+id/BtnShortcut"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Switch
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="[Open Now] Force load from local cache"
|
||||
android:padding="10dp"
|
||||
android:checked="true"
|
||||
android:id="@+id/SwitchCache"/>
|
||||
|
||||
</LinearLayout>
|
14
app/src/main/res/layout/webwindow.xml
Normal file
14
app/src/main/res/layout/webwindow.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/LayMain">
|
||||
|
||||
<WebView
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/Web0"/>
|
||||
|
||||
</LinearLayout>
|
5
app/src/main/res/values-v21/styles.xml
Normal file
5
app/src/main/res/values-v21/styles.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppTheme" parent="@android:style/Theme.Material.Light">
|
||||
</style>
|
||||
</resources>
|
4
app/src/main/res/values/strings.xml
Normal file
4
app/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">browserocto</string>
|
||||
</resources>
|
5
app/src/main/res/values/styles.xml
Normal file
5
app/src/main/res/values/styles.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppTheme" parent="@android:style/Theme.Holo.Light">
|
||||
</style>
|
||||
</resources>
|
Reference in New Issue
Block a user