Skip to content

Commit

Permalink
Add android app
Browse files Browse the repository at this point in the history
  • Loading branch information
mantikafasi committed Jun 13, 2023
1 parent 0fd0077 commit f6293b7
Show file tree
Hide file tree
Showing 44 changed files with 1,141 additions and 0 deletions.
10 changes: 10 additions & 0 deletions Android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
*.iml
.gradle
/local.properties
/.idea/*
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
1 change: 1 addition & 0 deletions Android/app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
44 changes: 44 additions & 0 deletions Android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
plugins {
id 'com.android.application'
}

android {
namespace 'dev.mantikafasi.MLock'
compileSdk 33

defaultConfig {
applicationId "dev.mantikafasi.MLock"
minSdk 24
targetSdk 33
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildFeatures {
viewBinding true
}
}

dependencies {

implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'androidx.navigation:navigation-fragment:2.4.1'
implementation 'androidx.navigation:navigation-ui:2.4.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
21 changes: 21 additions & 0 deletions Android/app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# 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 *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
40 changes: 40 additions & 0 deletions Android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.MLock"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<receiver
android:name=".MLockWidget"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>

<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/m_lock_widget_info" />
</receiver>

<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.MLock.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
58 changes: 58 additions & 0 deletions Android/app/src/main/java/dev/mantikafasi/MLock/API.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package dev.mantikafasi.MLock;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;

public class API {
public static void makeApiRequest(RequestType requestType, String API_URL, String password) throws Exception {
String suffix = "";

switch (requestType) {
case LOCK:
suffix = "/lock";
break;
case UNLOCK:
suffix = "/unlock";
break;
}

suffix += "?password=" + password;
String finalSuffix = suffix;
HttpURLConnection connection = null;

try {
URL url = new URL("http://" + API_URL + finalSuffix);
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(1500); // We dont want it to wait forever
connection.setRequestMethod("GET");

int responseCode = connection.getResponseCode();
switch (responseCode) {
case HttpURLConnection.HTTP_OK:
break;
case HttpURLConnection.HTTP_UNAUTHORIZED:
throw new Exception("Wrong password");
default:
throw new Exception("An error occured while processing your request");
}

} catch (SocketTimeoutException e) {
e.printStackTrace();
throw new Exception("Couldnt connect to the server, are you sure MLock is running and accessible?");
} catch (IOException e) {
e.printStackTrace();
throw new Exception("An error occured while processing your request");
} finally {
if (connection != null) {
connection.disconnect();
}
}
}

enum RequestType {
LOCK,
UNLOCK
}
}
92 changes: 92 additions & 0 deletions Android/app/src/main/java/dev/mantikafasi/MLock/MLockWidget.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package dev.mantikafasi.MLock;

import static android.content.Context.MODE_PRIVATE;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Looper;
import android.widget.RemoteViews;
import android.widget.Toast;

import java.util.Objects;

/**
* Implementation of App Widget functionality.
*/
public class MLockWidget extends AppWidgetProvider {
private static final String OnLock = "onLock";
private static final String OnUnlock = "OnUnlock";
SharedPreferences sharedPreferences;
RemoteViews views;
android.os.Handler mainHandler = new android.os.Handler(Looper.getMainLooper());
Context ctx;

void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {

views = new RemoteViews(context.getPackageName(), R.layout.m_lock_widget);

views.setOnClickPendingIntent(R.id.buttonLock, getPendingSelfIntent(context, OnLock));
views.setOnClickPendingIntent(R.id.buttonUnlock, getPendingSelfIntent(context, OnUnlock));
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}

protected PendingIntent getPendingSelfIntent(Context context, String action) {
Intent intent = new Intent(context, getClass());
intent.setAction(action);
return PendingIntent.getBroadcast(context, 0, intent, 0);
}

@Override
public void onReceive(Context context, Intent intent) {
if (!intent.getAction().equals(OnLock) && !intent.getAction().equals(OnUnlock)) {
super.onReceive(context, intent);
return;
}

ctx = context;

sharedPreferences = context.getSharedPreferences("MLock", MODE_PRIVATE);
String ip = sharedPreferences.getString("ipAddress", "");
String pass = sharedPreferences.getString("password", "");
if (ip.isEmpty() || pass.isEmpty()) {
toast("Please set IP and Password from app");
return;
}

new Thread(() -> {
try {
API.makeApiRequest(
Objects.equals(intent.getAction(), OnLock)
? API.RequestType.LOCK
: API.RequestType.UNLOCK,
ip,
pass
);
toast("Successfully" + (Objects.equals(intent.getAction(), OnLock) ? "Locked" : "Unlocked" + "computer"));
} catch (Exception e) {
mainHandler.post(() -> toast(e.getMessage()));
}
}).start();

super.onReceive(context, intent);
}

public void toast(String text) {
mainHandler.post(() ->
Toast.makeText(ctx, text, text.length() < 15 ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG).show());
}

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
}
81 changes: 81 additions & 0 deletions Android/app/src/main/java/dev/mantikafasi/MLock/MainActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package dev.mantikafasi.MLock;

import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import dev.mantikafasi.MLock.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {
ActivityMainBinding binding;
EditText ipAddressEditText;
EditText passwordEditText;

SharedPreferences sharedPreferences;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

sharedPreferences = getSharedPreferences("MLock", MODE_PRIVATE);

ipAddressEditText = findViewById(R.id.editTextIPAddress);
passwordEditText = findViewById(R.id.editTextPassword);

ipAddressEditText.setText(sharedPreferences.getString("ipAddress", ""));
passwordEditText.setText(sharedPreferences.getString("password", ""));
}

public void onUnlockComputerButtonClicked(View v) {
if (!validateInput()) {
return;
}

new Thread(() -> {
try {
API.makeApiRequest(API.RequestType.UNLOCK, ipAddressEditText.getText().toString(), passwordEditText.getText().toString());
toast("Successfully unlocked");
} catch (Exception e) {
toast(e.getMessage());
}
}).start();
}

public void onLockComputerButtonClicked(View v) {
if (!validateInput()) {
return;
}

new Thread(() -> {
try {
API.makeApiRequest(API.RequestType.LOCK, ipAddressEditText.getText().toString(), passwordEditText.getText().toString());
toast("Successfully locked");
} catch (Exception e) {
toast(e.getMessage());
}
}).start();
}

public void toast(String text) {
runOnUiThread(() ->
Toast.makeText(MainActivity.this, text, text.length() < 15 ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG).show());
}

public boolean validateInput() {
String ipAdress = ipAddressEditText.getText().toString();
String password = passwordEditText.getText().toString();

if (ipAdress.isEmpty() || password.isEmpty()) {
Toast.makeText(MainActivity.this, "Please fill the form above", Toast.LENGTH_SHORT).show();
return false;
}
sharedPreferences.edit().putString("ipAddress", ipAdress).putString("password", password).apply();
return true;
}
}
10 changes: 10 additions & 0 deletions Android/app/src/main/res/drawable-v21/app_widget_background.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?><!--
Background for widgets to make the rounded corners based on the
appWidgetRadius attribute value
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<corners android:radius="?attr/appWidgetRadius" />
<solid android:color="?android:attr/colorBackground" />
</shape>
Loading

0 comments on commit f6293b7

Please sign in to comment.