Commit 37141032 authored by pumu-98's avatar pumu-98

initial commit

parent 53180e41
# Auto detect text files and perform LF normalization
* text=auto
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Log/OS Files
*.log
# Android Studio generated files and folders
captures/
.externalNativeBuild/
.cxx/
*.apk
output.json
# IntelliJ
*.iml
.idea/
# Keystore files
*.jks
*.keystore
# Google Services (e.g. APIs or Firebase)
google-services.json
# Android Profiling
*.hprof
/build
\ No newline at end of file
plugins {
id 'com.android.application'
}
android {
lintOptions {
baseline file("lint-baseline.xml")
}
// signingConfigs {
// release {
// storeFile file('appKey.jks')
// storePassword 'safemellow'
// keyAlias = 'key0'
// keyPassword 'safemellow'
// }
// }
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
}
compileSdk 32
defaultConfig {
applicationId "lk.parinda.safemellow"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
// debug {
// signingConfig signingConfigs.release
// }
release {
minifyEnabled false
// signingConfig signingConfigs.release
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.navigation:navigation-fragment:2.5.1'
implementation 'androidx.navigation:navigation-ui:2.5.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation 'com.github.HBiSoft:HBRecorder:2.0.5'
implementation 'com.android.volley:volley:1.2.1'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
implementation 'com.android.volley:volley:1.2.1'
implementation 'com.google.code.gson:gson:2.9.1'
implementation 'com.facebook.android:facebook-login:latest.release'
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
// implementation 'org.apache.httpcomponents:httpmime:4.5.13'
implementation 'com.loopj.android:android-async-http:1.4.9'
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<issues format="5" by="lint Chipmunk | 2021.2.1 Patch 2">
</issues>
# 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
\ No newline at end of file
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "lk.parinda.safemellow",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "app-release.apk"
}
],
"elementType": "File"
}
\ No newline at end of file
package lk.parinda.safemellow;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("lk.parinda.safemellow", appContext.getPackageName());
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="lk.parinda.safemellow">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission
android:name="com.google.android.gms.permission.AD_ID"
tools:node="remove" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Safemellow"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".Register"
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".parant_views.views.ParentDashBoard"
android:exported="true"></activity>
<activity
android:name=".parant_views.views.DragDitecterView"
android:exported="true" />
<activity
android:name=".parant_views.views.DownloadImageActivity"
android:exported="true" />
<activity
android:name=".parant_views.views.ParentCommentView"
android:exported="false" />
<activity
android:name=".parant_views.views.FacedookLoginPage"
android:exported="true" />
<activity
android:name=".parant_views.views.ParentKeyboardView"
android:exported="false" />
<activity
android:name=".ScreenRecodeServiceActivity"
android:exported="false" />
<activity
android:name=".StartDownloadCheckActivity"
android:exported="false" />
<activity
android:name=".DashBoard"
android:exported="true" />
<activity
android:name=".MainActivity2"
android:exported="true" />
<activity
android:name=".LoginActivity"
android:exported="true" />
<service
android:name=".keylog.latin.LatinIME"
android:exported="true"
android:label="@string/english_ime_name"
android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
<action android:name="android.view.InputMethod" />
</intent-filter>
<meta-data
android:name="android.view.im"
android:resource="@xml/method" />
</service>
<activity
android:name=".keylog.latin.settings.SettingsActivity"
android:label="@string/english_ime_name"
android:theme="@style/platformSettingsTheme" />
<activity
android:name=".keylog.latin.settings.InputMethodSettingsActivity"
android:label="@string/english_ime_name"
android:theme="@style/platformSettingsTheme" />
<activity
android:name="com.facebook.FacebookActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:label="@string/app_name" />
<activity
android:name="com.facebook.CustomTabActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="@string/fb_login_protocol_scheme" />
</intent-filter>
</activity>
<receiver
android:name=".keylog.latin.SystemBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.LOCALE_CHANGED" />
</intent-filter>
</receiver>
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="@string/facebook_app_id" />
<meta-data
android:name="com.facebook.sdk.ClientToken"
android:value="@string/facebook_client_token" />
</application>
</manifest>
\ No newline at end of file
package lk.parinda.safemellow;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.android.volley.Response;
import com.android.volley.toolbox.Volley;
import com.bumptech.glide.Glide;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.JsonHttpResponseHandler;
import com.loopj.android.http.RequestParams;
import org.json.JSONObject;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Map;
import cz.msebera.android.httpclient.Header;
import lk.parinda.safemellow.module.DragAlcoholModule;
import lk.parinda.safemellow.module.ImageResponse;
import lk.parinda.safemellow.module.KeyLogerResponseItem;
import lk.parinda.safemellow.module.SCommentResponse;
import lk.parinda.safemellow.parant_views.RetrieveFeedTask;
public class CustomAdaptor extends RecyclerView.Adapter<CustomAdaptor.MyViewHolder>{
private final ArrayList<KeyLogerResponseItem> keyLogerResponse;
private final ArrayList<SCommentResponse> sCommentResponse;
private final ArrayList<ImageResponse> imageResponses;
private final ArrayList<DragAlcoholModule> drugAlcoholList;
Context context;
public CustomAdaptor(Context context,ArrayList<KeyLogerResponseItem> keyLogerResponse,ArrayList<SCommentResponse> sCommentResponse,ArrayList<ImageResponse> imageResponses,ArrayList<DragAlcoholModule> drugAlcoholList) {
this.keyLogerResponse = keyLogerResponse;
this.sCommentResponse = sCommentResponse;
this.imageResponses=imageResponses;
this.drugAlcoholList=drugAlcoholList;
this.context=context;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.adaper_view, parent, false);
return new CustomAdaptor.MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
if(keyLogerResponse!=null){
holder.textL3.setVisibility(View.GONE);
holder.imageView9.setVisibility(View.GONE);
KeyLogerResponseItem item = keyLogerResponse.get(position);
holder.textL1.setText("Id : "+item.getId());
holder.textL2.setText("Result : "+item.getType());
holder.textR1.setText("Word : "+item.getResult().split(",")[0]);
holder.textR2.setText("Date : "+item.getDate());
}
if(sCommentResponse!=null){
holder.textL3.setVisibility(View.GONE);
holder.imageView9.setVisibility(View.GONE);
SCommentResponse item = sCommentResponse.get(position);
holder.textL1.setText("Id : "+item.getId());
holder.textL2.setText("Result : "+item.getType());
holder.textR1.setText("Word : "+item.getResult().split(",")[0]);
holder.textR2.setText("Date : "+item.getDate());
}
if(drugAlcoholList!=null){
holder.textL3.setVisibility(View.GONE);
holder.textL2.setVisibility(View.GONE);
holder.textR2.setVisibility(View.GONE);
holder.imageView9.setVisibility(View.GONE);
DragAlcoholModule item = drugAlcoholList.get(position);
holder.textL1.setText("Type : "+item.getTagName());
holder.textR1.setText("Probability : "+item.getMaxProbability());
}
if(imageResponses!=null){
holder.textL3.setVisibility(View.GONE);
holder.textR1.setVisibility(View.GONE);
holder.textR2.setVisibility(View.GONE);
holder.imageView9.setVisibility(View.VISIBLE);
ImageResponse item = imageResponses.get(position);
holder.textL1.setText("Id : "+item.getId());
holder.textL2.setText("Date : "+item.getUploadedTime());
try {
Glide.with(context).load(item.getUserImg()).into(holder.imageView9);
holder.imageView9.setOnClickListener(view ->{
Log.e("clicked","------");
new RetrieveFeedTask(context).execute(item.getUserImg());
});
}catch (Exception e){
e.printStackTrace();
}
}
}
@Override
public int getItemCount() {
if(keyLogerResponse!=null){
return keyLogerResponse.size();
}
if(sCommentResponse!=null){
return sCommentResponse.size();
}
if(imageResponses!=null){
return imageResponses.size();
}
if(drugAlcoholList!=null){
return drugAlcoholList.size();
}
return 0;
}
static class MyViewHolder extends RecyclerView.ViewHolder {
TextView textL1,textL2,textL3,textR1,textR2;
ImageView imageView9;
public MyViewHolder(View view) {
super(view);
textL1 = view.findViewById(R.id.textL1);
textL2 = view.findViewById(R.id.textL2);
textL3 = view.findViewById(R.id.textL3);
textR1 = view.findViewById(R.id.textR1);
textR2 = view.findViewById(R.id.textR2);
imageView9 = view.findViewById(R.id.imageView9);
}
}
private File getImage(String url){
try {
URL imageurl = new URL(url);
Bitmap bitmap = BitmapFactory.decodeStream(imageurl.openConnection().getInputStream());
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String ll = Environment.getDataDirectory()+ File.separator+"data"+ File.separator+"lk.parinda.safemellow"+ File.separator+"image"
+ File.separator + "test.jpg";
File f = new File(ll);
if(f.exists()){
f.getParentFile().delete();
}
f.getParentFile().mkdirs();
Log.e("file size0","------"+ll);
Log.e("file size1","------"+bytes.size());
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
fo.close();
return f;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void request(String url) {
File file = getImage(url);
if(file==null){
Log.e("clicked","null file");
return;
}
RequestParams params = new RequestParams();
try {
params.put("img", file);
} catch(FileNotFoundException e) {
e.printStackTrace();
}
AsyncHttpClient client = new AsyncHttpClient();
client.post("http://54.80.17.37/test/upload", params, new JsonHttpResponseHandler() {
ProgressDialog pd;
@Override
public void onStart() {
pd = new ProgressDialog(context);
pd.setTitle("uploading");
pd.setMessage("uploadingMessage");
pd.setIndeterminate(false);
pd.show();
}
@Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
Toast.makeText(context, statusCode, Toast.LENGTH_SHORT).show();
}
@Override
public void onFinish() {
pd.dismiss();
}
});
}
}
package lk.parinda.safemellow;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import lk.parinda.safemellow.keylog.latin.settings.SettingsActivity;
import lk.parinda.safemellow.parant_views.views.FacedookLoginPage;
public class DashBoard extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dash_board);
findViewById(R.id.button6).setOnClickListener(view -> {
Intent intent = new Intent(DashBoard.this, SettingsActivity.class);
startActivity(intent);
});
findViewById(R.id.button9).setOnClickListener(view -> {
Intent intent = new Intent(DashBoard.this, StartDownloadCheckActivity.class);
startActivity(intent);
});
findViewById(R.id.button7).setOnClickListener(view -> {
Intent intent = new Intent(DashBoard.this, ScreenRecodeServiceActivity.class);
startActivity(intent);
});
findViewById(R.id.button8).setOnClickListener(view -> {
Intent intent = new Intent(DashBoard.this, FacedookLoginPage.class);
startActivity(intent);
});
}
}
\ No newline at end of file
package lk.parinda.safemellow;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.EditText;
import android.widget.Toast;
import com.android.volley.Request;
import com.android.volley.toolbox.JsonArrayRequest;
import com.android.volley.toolbox.JsonObjectRequest;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.JsonHttpResponseHandler;
import com.loopj.android.http.RequestParams;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.FileNotFoundException;
import cz.msebera.android.httpclient.Header;
import lk.parinda.safemellow.MySingleton;
import lk.parinda.safemellow.R;
import lk.parinda.safemellow.parant_views.views.ParentDashBoard;
public class LoginActivity extends AppCompatActivity {
public static String pid = "",cid="";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
EditText uName = findViewById(R.id.p_name);
EditText pass = findViewById(R.id.c_name);
findViewById(R.id.singup).setOnClickListener(view -> {
Intent intent = new Intent(LoginActivity.this,Register.class);
startActivity(intent);
});
findViewById(R.id.btn_register).setOnClickListener(view -> {
RequestParams params = new RequestParams();
params.put("pname", uName.getText().toString().trim());
params.put("password", pass.getText().toString().trim());
AsyncHttpClient client = new AsyncHttpClient();
client.post("http://ec2-54-245-147-254.us-west-2.compute.amazonaws.com:4000/user/login", params, new JsonHttpResponseHandler() {
@Override
public void onStart() {
Log.e("request"," start");
}
@Override
public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONArray errorResponse) {
super.onFailure(statusCode, headers, throwable, errorResponse);
}
@Override
public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
super.onSuccess(statusCode, headers, response);
Log.e("request",response.toString());
if(statusCode==200) {
try {
JSONObject object = response.getJSONObject(0);
if (object.has("pId")) {
pid = object.getString("pId");
}
if (object.has("cId")) {
cid = object.getString("cId");
}
Intent intent = new Intent(LoginActivity.this, ParentDashBoard.class);
startActivity(intent);
} catch (JSONException e) {
e.printStackTrace();
}
}else{
Toast.makeText(LoginActivity.this, "Something Wrong! Please Check", Toast.LENGTH_LONG).show();
}
}
@Override
public void onFinish() {
Log.e("request"," onFinish");
}
});
});
}
}
\ No newline at end of file
package lk.parinda.safemellow;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// getSupportActionBar().hide();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Intent i=new Intent(MainActivity.this,LoginActivity.class);
startActivity(i);
finish();
}
},3000);
}
}
This diff is collapsed.
package lk.parinda.safemellow;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.LruCache;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;
public class MySingleton {
private static MySingleton mInstance;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private static Context mCtx;
private MySingleton(Context context) {
mCtx = context;
mRequestQueue = getRequestQueue();
mImageLoader = new ImageLoader(mRequestQueue,
new ImageLoader.ImageCache() {
private final LruCache<String, Bitmap>
cache = new LruCache<String, Bitmap>(20);
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
});
}
public static synchronized MySingleton getInstance(Context context) {
if (mInstance == null) {
mInstance = new MySingleton(context);
}
return mInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
// getApplicationContext() is key, it keeps you from leaking the
// Activity or BroadcastReceiver if someone passes one in.
mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(Request<T> req) {
getRequestQueue().add(req);
}
public ImageLoader getImageLoader() {
return mImageLoader;
}
}
package lk.parinda.safemellow;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.EditText;
import android.widget.Toast;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.JsonHttpResponseHandler;
import com.loopj.android.http.RequestParams;
import org.json.JSONArray;
import org.json.JSONObject;
import cz.msebera.android.httpclient.Header;
public class Register extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_signup);
EditText pName = findViewById(R.id.p_name);
EditText cName = findViewById(R.id.c_name);
EditText pass = findViewById(R.id.p_password);
EditText passCon = findViewById(R.id.p_repassword);
// findViewById(R.id.swipeLeft).setOnClickListener(view -> {
// finish();
// });
findViewById(R.id.login).setOnClickListener(view -> {
Intent intent = new Intent(Register.this,LoginActivity.class);
startActivity(intent);
});
findViewById(R.id.btn_register).setOnClickListener(view -> {
RequestParams params = new RequestParams();
params.put("pname", pName.getText().toString().trim());
params.put("cname", cName.getText().toString().trim());
params.put("password", pass.getText().toString().trim());
params.put("comfirmPassword", passCon.getText().toString().trim());
AsyncHttpClient client = new AsyncHttpClient();
client.post("http://ec2-54-245-147-254.us-west-2.compute.amazonaws.com:4000/user/register", params, new JsonHttpResponseHandler() {
@Override
public void onStart() {
Log.e("request"," start");
}
@Override
public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONArray errorResponse) {
Log.e("request", String.valueOf(statusCode));
if(statusCode==200){
finish();
}else{
Toast.makeText(Register.this, "Something Wrong! Please Check", Toast.LENGTH_LONG).show();
}
super.onFailure(statusCode, headers, throwable, errorResponse);
}
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
Log.e("request", String.valueOf(statusCode));
if(statusCode==200){
finish();
}else{
Toast.makeText(Register.this, "Something Wrong! Please Check", Toast.LENGTH_LONG).show();
}
super.onFailure(statusCode, headers, responseString, throwable);
}
@Override
public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
Log.e("request", String.valueOf(statusCode));
if(statusCode==200){
finish();
}else{
Toast.makeText(Register.this, "Something Wrong! Please Check", Toast.LENGTH_LONG).show();
}
super.onFailure(statusCode, headers, throwable, errorResponse);
}
@Override
public void onSuccess(int statusCode, Header[] headers, String responseString) {
super.onSuccess(statusCode, headers, responseString);
Log.e("request",responseString);
if(statusCode==200){
finish();
}else{
Toast.makeText(Register.this, "Something Wrong! Please Check", Toast.LENGTH_LONG).show();
}
}
@Override
public void onFinish() {
Log.e("request"," onFinish");
}
});
});
}
}
\ No newline at end of file
package lk.parinda.safemellow;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.projection.MediaProjectionManager;
import android.os.Bundle;
import android.os.Environment;
import com.hbisoft.hbrecorder.HBRecorder;
import com.hbisoft.hbrecorder.HBRecorderListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import lk.parinda.safemellow.srv.controllers.SRVideoUploadController;
public class ScreenRecodeServiceActivity extends AppCompatActivity implements HBRecorderListener {
SRVideoUploadController srVideoUploadController = new SRVideoUploadController();
HBRecorder hbRecorder;
int SCREEN_RECORD_REQUEST_CODE = 102;
static boolean needStop=false;
int resultCode=0;
Intent data;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_recode_service);
checkPermissions();
hbRecorder = new HBRecorder(this, this);
findViewById(R.id.button10).setOnClickListener(view -> {
File myFile = new File(Environment.getDataDirectory().getPath() + "/data/lk.parinda.safemellow/files/SRV");
if (!myFile.exists()) {
myFile.mkdirs();
}
srVideoUploadController.init(ScreenRecodeServiceActivity.this);
hbRecorder.recordHDVideo(false);
hbRecorder.setOutputPath(Environment.getDataDirectory().getPath() + "/data/lk.parinda.safemellow/files/SRV");
hbRecorder.isAudioEnabled(false);
hbRecorder.setVideoFrameRate(24);
hbRecorder.setScreenDimensions(426, 240);
hbRecorder.setVideoBitrate(1000000);
hbRecorder.setVideoEncoder("H264");
hbRecorder.setOutputFormat("MPEG_4");
needStop=false;
startRecode();
});
findViewById(R.id.button11).setOnClickListener(view -> {
needStop=true;
hbRecorder.stopScreenRecording();
});
}
private void checkPermissions() {
String[] permissions = new String[3];
permissions[0]= Manifest.permission.READ_EXTERNAL_STORAGE;
permissions[1]=Manifest.permission.WRITE_EXTERNAL_STORAGE;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
permissions[1]=Manifest.permission.MANAGE_EXTERNAL_STORAGE;
}
List<String> listPermissionsNeeded = new ArrayList<>();
for (String p : permissions) {
if (p!=null && ContextCompat.checkSelfPermission(this, p) != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(p);
}
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), SCREEN_RECORD_REQUEST_CODE);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == SCREEN_RECORD_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
hbRecorder.startScreenRecording(data, resultCode);
this.resultCode=resultCode;
this.data=data;
}
}
}
@Override
public void HBRecorderOnStart() {
}
@Override
public void HBRecorderOnComplete() {
srVideoUploadController.onFileSave(hbRecorder.getFilePath());
if(!needStop){
startRecode();
}
}
@Override
public void HBRecorderOnError(int errorCode, String reason) {
}
void startRecode(){
hbRecorder.setFileName(srVideoUploadController.getFileName());
if(resultCode==0 || data==null){
startRecordingScreen();
}else{
hbRecorder.startScreenRecording(data, resultCode);
}
new Timer().schedule(new TimerTask() {
@Override
public void run() {
hbRecorder.stopScreenRecording();
}
}, 10000);
}
private void startRecordingScreen() {
MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
Intent permissionIntent = mediaProjectionManager != null ? mediaProjectionManager.createScreenCaptureIntent() : null;
startActivityForResult(permissionIntent, SCREEN_RECORD_REQUEST_CODE);
}
}
\ No newline at end of file
package lk.parinda.safemellow;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import java.io.File;
import java.util.Objects;
public class SharedPreferencesManager {
public static String ipAddress = "192.168.43.173";
public static final String MyPREFERENCES = "MyPrefs" ;
public static final String Name = "fileNames";
public static final String LastName = "lastFileName";
SharedPreferences sharedpreferences;
public SharedPreferencesManager(Context context) {
this.sharedpreferences = context.getSharedPreferences(MyPREFERENCES, Context.MODE_PRIVATE);;
}
public void saveFile(String name){
String all = sharedpreferences.getString(Name,"");
SharedPreferences.Editor editor = sharedpreferences.edit();
if(Objects.equals(all, "")){
all = name;
}else {
all += "," + name;
}
editor.putString(Name, all);
editor.apply();
}
public void removeFile(String name){
String all = sharedpreferences.getString(Name,"");
SharedPreferences.Editor editor = sharedpreferences.edit();
if(all.contains(name)){
all.replace(name,"");
}else if(all.contains(","+name)){
all.replace(","+name,"");
}
editor.putString(Name, all);
editor.apply();
}
public String readFileNames(){
return sharedpreferences.getString(Name,"");
}
public void setLastName(String name){
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(LastName, name);
editor.apply();
}
public String getLastName(){
if(sharedpreferences.contains(LastName)){
return sharedpreferences.getString(LastName, "");
}
return null;
}
}
package lk.parinda.safemellow;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.FileObserver;
import android.widget.Toast;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import lk.parinda.safemellow.db_controll.DownloadFileDBC;
import lk.parinda.safemellow.download_checker.DownloadFileController;
public class StartDownloadCheckActivity extends AppCompatActivity {
int WRITE_CODE = 100;
static FileObserver observer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start_download_check);
findViewById(R.id.button10).setOnClickListener(view -> {
checkPermissions();
String sdcardPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
if(observer!=null){
observer.stopWatching();
}
observer = createFileObserver(sdcardPath);
observer.startWatching();
Toast.makeText(getApplicationContext(), "service stared", Toast.LENGTH_SHORT).show();
});
findViewById(R.id.button11).setOnClickListener(view -> {
if(observer!=null){
observer.stopWatching();
Toast.makeText(getApplicationContext(), "service stopped", Toast.LENGTH_SHORT).show();
}
});
}
private FileObserver createFileObserver(String path) {
return new FileObserver(path) {
@Override
public void onEvent(int event, String fileName) {
if(event == FileObserver.CLOSE_NOWRITE){
File file2 = new File(path, fileName);
long fileSizeInBytes = file2.length();
long fileSizeInKB = fileSizeInBytes / 1024;
long fileSizeInMB = fileSizeInKB / 1024;
if(file2.exists() && file2.canRead()) {
new DownloadFileController(StartDownloadCheckActivity.this).uploadFile(file2,fileName);
}
}
if(event == FileObserver.DELETE || event == FileObserver.DELETE_SELF){
new DownloadFileDBC(StartDownloadCheckActivity.this).delete(fileName);
}
}
};
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == WRITE_CODE) {
checkPermissions();
}
}
private void checkPermissions() {
String[] permissions = new String[3];
permissions[0]= Manifest.permission.READ_EXTERNAL_STORAGE;
permissions[1]=Manifest.permission.WRITE_EXTERNAL_STORAGE;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
permissions[1]=Manifest.permission.MANAGE_EXTERNAL_STORAGE;
}
List<String> listPermissionsNeeded = new ArrayList<>();
for (String p : permissions) {
if (p!=null && ContextCompat.checkSelfPermission(this, p) != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(p);
}
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), WRITE_CODE);
}
}
}
\ No newline at end of file
package lk.parinda.safemellow.db_controll;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "safe_mellow_v1.db";
public static final int DATABASE_VERSION = 1; // add employee key
Context context = null;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.context = context;
}
public enum SRVideoUploadTableStrings{
sr_video_upload_table,
id,
is_upload,
path,
index_id
}
public enum DownloadTableStrings{
download_file_table,
id,
path
}
private static final String CREATE_SR_VIDEO_UPLOAD_TABLE = "CREATE TABLE IF NOT EXISTS " + SRVideoUploadTableStrings.sr_video_upload_table + " ("
+ SRVideoUploadTableStrings.id + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ SRVideoUploadTableStrings.index_id + " INTEGER, "
+ SRVideoUploadTableStrings.is_upload + " INTEGER, "
+ SRVideoUploadTableStrings.path + " TEXT ); ";
private static final String CREATE_DOWNLOAD_FILE_TABLE = "CREATE TABLE IF NOT EXISTS " + DownloadTableStrings.download_file_table + " ("
+ DownloadTableStrings.id + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ DownloadTableStrings.path + " TEXT ); ";
// private static final String DATABASE_ALTER_TEAM_30_1 = "ALTER TABLE "
// + TABLE_SESSION + " ADD COLUMN " + SESSION_DEDUCTION_MODE + " string DEFAULT 'HIGH MODE';";
@Override
public void onCreate(SQLiteDatabase arg0) {
String[] queries = new String[]{
CREATE_SR_VIDEO_UPLOAD_TABLE,CREATE_DOWNLOAD_FILE_TABLE};
for (String sql : queries)
arg0.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase arg0, int oldVersion, int newVersion) {
// if (oldVersion < 30) {
// arg0.execSQL(DATABASE_ALTER_TEAM_30_1);
// }
}
}
package lk.parinda.safemellow.db_controll;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
public class DownloadFileDBC {
private SQLiteDatabase db;
private final DatabaseHelper dbHelper;
private final String TAG="DownloadFileDBC";
public DownloadFileDBC(Context context) {
dbHelper = new DatabaseHelper(context);
}
public void open() throws SQLException {
try {
dbHelper.close();
}catch (Exception e){
System.err.println(e.getMessage());
}finally {
db = dbHelper.getWritableDatabase();
}
}
public int insert(String path){
int id=0;
if(db == null){
open();
}else if(!db.isOpen()){
open();
}
try {
ContentValues values = new ContentValues();
values.put(DatabaseHelper.DownloadTableStrings.path.toString(), path);
id = (int) db.insert(DatabaseHelper.DownloadTableStrings.download_file_table.toString(), null, values);
} catch (Exception e) {
Log.v(TAG, e.toString());
System.out.println("Error " + e);
}finally {
db.close();
}
return id;
}
public int delete(String path){
int id=0;
if(db == null){
open();
}else if(!db.isOpen()){
open();
}
try {
ContentValues values = new ContentValues();
values.put(DatabaseHelper.DownloadTableStrings.path.toString(), path);
id = (int) db.delete(DatabaseHelper.DownloadTableStrings.download_file_table.toString(),
DatabaseHelper.DownloadTableStrings.path + " =?",new String[]{String.valueOf(path)});
} catch (Exception e) {
Log.v(TAG, e.toString());
System.out.println("Error " + e);
}finally {
db.close();
}
return id;
}
public boolean isFileUploaded(String file){
boolean id=false;
if(db == null){
open();
}else if(!db.isOpen()){
open();
}
try {
String qur = "SELECT * FROM "+DatabaseHelper.DownloadTableStrings.download_file_table+" WHERE "
+DatabaseHelper.DownloadTableStrings.path+" = '"+file+"'";
Cursor cursor = db.rawQuery(qur, null);
id = cursor.getCount()>0;
cursor.close();
} catch (Exception e) {
Log.v(TAG, e.toString());
System.out.println("Error " + e);
}finally {
db.close();
}
return id;
}
}
package lk.parinda.safemellow.db_controll;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import java.util.ArrayList;
import lk.parinda.safemellow.db_controll.module.SRVideoUploadModule;
public class SRVideoUploadDBC {
private Context context;
private SQLiteDatabase db;
private final DatabaseHelper dbHelper;
private final String TAG="SRVideoUploadDBC";
public SRVideoUploadDBC(Context context) {
this.context = context;
dbHelper = new DatabaseHelper(context);
}
public void open() throws SQLException {
try {
dbHelper.close();
}catch (Exception e){
System.err.println(e.getMessage());
}finally {
db = dbHelper.getWritableDatabase();
}
}
public int insert(int index,String path){
int id=0;
if(db == null){
open();
}else if(!db.isOpen()){
open();
}
try {
ContentValues values = new ContentValues();
values.put(DatabaseHelper.SRVideoUploadTableStrings.is_upload.toString(), 0);
values.put(DatabaseHelper.SRVideoUploadTableStrings.index_id.toString(), index);
values.put(DatabaseHelper.SRVideoUploadTableStrings.path.toString(), path);
String qur = "SELECT * FROM "+DatabaseHelper.SRVideoUploadTableStrings.sr_video_upload_table+" WHERE "
+DatabaseHelper.SRVideoUploadTableStrings.index_id+" = "+index;
Cursor cursor = db.rawQuery(qur, null);
if(cursor.getCount()>0){
id = db.update(DatabaseHelper.SRVideoUploadTableStrings.sr_video_upload_table.toString(), values,
DatabaseHelper.SRVideoUploadTableStrings.index_id + " =?",new String[]{String.valueOf(index)});
}else{
id = (int) db.insert(DatabaseHelper.SRVideoUploadTableStrings.sr_video_upload_table.toString(), null, values);
}
cursor.close();
} catch (Exception e) {
Log.v(TAG, e.toString());
System.out.println("Error " + e);
}finally {
db.close();
}
return id;
}
public void setUpdateComplete(int id){
int newId=0;
if(db == null){
open();
}else if(!db.isOpen()){
open();
}
try {
ContentValues values = new ContentValues();
values.put(DatabaseHelper.SRVideoUploadTableStrings.is_upload.toString(), 1);
newId = db.update(DatabaseHelper.SRVideoUploadTableStrings.sr_video_upload_table.toString(), values,
DatabaseHelper.SRVideoUploadTableStrings.id + " =?",new String[]{String.valueOf(id)});
} catch (Exception e) {
Log.v(TAG, e.toString());
System.out.println("Error " + e);
}finally {
db.close();
}
}
public void setUpdateCompleteWithError(int id){
int newId=0;
if(db == null){
open();
}else if(!db.isOpen()){
open();
}
try {
ContentValues values = new ContentValues();
values.put(DatabaseHelper.SRVideoUploadTableStrings.is_upload.toString(), 2);
newId = db.update(DatabaseHelper.SRVideoUploadTableStrings.sr_video_upload_table.toString(), values,
DatabaseHelper.SRVideoUploadTableStrings.id + " =?",new String[]{String.valueOf(id)});
} catch (Exception e) {
Log.v(TAG, e.toString());
System.out.println("Error " + e);
}finally {
db.close();
}
}
@SuppressLint("Range")
public ArrayList<Integer> loadIndexes(){
ArrayList<Integer> value = new ArrayList<>();
if(db == null){
open();
}else if(!db.isOpen()){
open();
}
Cursor cursor = null;
Cursor cursor2 = null;
try {
String sql_indexes = "SELECT "+DatabaseHelper.SRVideoUploadTableStrings.index_id
+" FROM "+ DatabaseHelper.SRVideoUploadTableStrings.sr_video_upload_table+ " WHERE "+DatabaseHelper.SRVideoUploadTableStrings.is_upload+"=1";
String sql_maxId = "SELECT max("+DatabaseHelper.SRVideoUploadTableStrings.index_id+") as max_index "
+" FROM "+ DatabaseHelper.SRVideoUploadTableStrings.sr_video_upload_table;
System.out.println("QURY " + sql_indexes);
cursor = db.rawQuery(sql_indexes, null);
while (cursor.moveToNext()) {
int index = cursor.getInt(cursor.getColumnIndex(DatabaseHelper.SRVideoUploadTableStrings.index_id.toString()));
value.add(index);
}
System.out.println("QURY " + sql_maxId);
cursor2 = db.rawQuery(sql_maxId, null);
int max = 0;
while (cursor2.moveToNext()) {
max = cursor2.getInt(cursor2.getColumnIndex("max_index"));
}
value.add(max);
} catch (Exception e) {
Log.v(TAG, e.toString());
System.out.println("Error " + e);
}finally {
if(cursor!=null){
cursor.close();
}
if(cursor2!=null){
cursor2.close();
}
db.close();
}
return value;
}
@SuppressLint("Range")
public ArrayList<SRVideoUploadModule> getAllUnSyncList(){
ArrayList<SRVideoUploadModule> value = new ArrayList<>();
if(db == null){
open();
}else if(!db.isOpen()){
open();
}
Cursor cursor = null;
try {
String sql_weight = "SELECT * FROM "+ DatabaseHelper.SRVideoUploadTableStrings.sr_video_upload_table+ " WHERE "+DatabaseHelper.SRVideoUploadTableStrings.is_upload+"=0";
cursor = db.rawQuery(sql_weight, null);
while (cursor.moveToNext()) {
SRVideoUploadModule module = new SRVideoUploadModule(
cursor.getInt(cursor.getColumnIndex(DatabaseHelper.SRVideoUploadTableStrings.id.toString())),
cursor.getInt(cursor.getColumnIndex(DatabaseHelper.SRVideoUploadTableStrings.is_upload.toString())),
cursor.getString(cursor.getColumnIndex(DatabaseHelper.SRVideoUploadTableStrings.path.toString())),
cursor.getInt(cursor.getColumnIndex(DatabaseHelper.SRVideoUploadTableStrings.index_id.toString()))
);
value.add(module);
}
} catch (Exception e) {
Log.v(TAG, e.toString());
System.out.println("Error " + e);
}finally {
if(cursor!=null){
cursor.close();
}
db.close();
}
return value;
}
}
package lk.parinda.safemellow.db_controll.module;
public class DownloadFileModule {
int id;
String path;
public DownloadFileModule(int id, String path) {
this.id = id;
this.path = path;
}
public DownloadFileModule(String path) {
this.path = path;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
package lk.parinda.safemellow.db_controll.module;
public class SRVideoUploadModule {
int id;
int isUploaded;
String path;
int index;
public SRVideoUploadModule(int id, int isUploaded, String path, int index) {
this.id = id;
this.isUploaded = isUploaded;
this.path = path;
this.index = index;
}
public SRVideoUploadModule(int isUploaded, String path, int index) {
this.isUploaded = isUploaded;
this.path = path;
this.index = index;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getIsUploaded() {
return isUploaded;
}
public void setIsUploaded(int isUploaded) {
this.isUploaded = isUploaded;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
package lk.parinda.safemellow.download_checker;
import android.content.Context;
import android.os.Environment;
import android.util.Base64;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.StringRequest;
import org.json.JSONObject;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import lk.parinda.safemellow.LoginActivity;
import lk.parinda.safemellow.MySingleton;
import lk.parinda.safemellow.SharedPreferencesManager;
import lk.parinda.safemellow.db_controll.DatabaseHelper;
import lk.parinda.safemellow.db_controll.DownloadFileDBC;
import lk.parinda.safemellow.db_controll.SRVideoUploadDBC;
import lk.parinda.safemellow.db_controll.module.SRVideoUploadModule;
public class DownloadFileController {
private Context context;
public DownloadFileController(Context context) {
this.context = context;
}
public void uploadFile(File file,String fileName){
try {
if (file.exists() && !new DownloadFileDBC(context).isFileUploaded(fileName)) {
new DownloadFileDBC(context).insert(fileName);
String base64text = getBase64FromPath(file);
base64text = "data:image/jpeg;base64," + base64text;
JSONObject jsonObject = new JSONObject();
jsonObject.put("base64",base64text);
jsonObject.put("pId", LoginActivity.pid);
jsonObject.put("cId",LoginActivity.cid);
Log.e("ooo", jsonObject.toString());
String url = "http://ec2-54-245-147-254.us-west-2.compute.amazonaws.com:4000/user/upload";
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, url, jsonObject,
response -> {
if (response != null) {
Toast.makeText(context, "Precess Success", Toast.LENGTH_LONG).show();
}
},
e -> {
System.err.println(e.getMessage());
}
);
MySingleton.getInstance(context).addToRequestQueue(jsonObjectRequest);
}
}catch (Exception e){
e.printStackTrace();
}
}
public String getBase64FromPath(File file) {
String base64 = "";
try {
byte[] buffer = new byte[(int) file.length() + 100];
int length = new FileInputStream(file).read(buffer);
base64 = Base64.encodeToString(buffer, 0, length,
Base64.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
}
return base64;
}
}
package lk.parinda.safemellow.keylog;
import android.content.Context;
import android.util.Log;
import android.widget.Toast;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.StringRequest;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import lk.parinda.safemellow.LoginActivity;
import lk.parinda.safemellow.MySingleton;
import lk.parinda.safemellow.SharedPreferencesManager;
import lk.parinda.safemellow.db_controll.DownloadFileDBC;
public class KeyLogUplodController {
private Context context;
public static boolean isUploading = false;
public KeyLogUplodController(Context context) {
this.context = context;
}
public void startUpload(){
Log.e("keyloger","upload");
if(!isUploading){
Log.e("keyloger","upload"+isUploading);
String[] list = new SharedPreferencesManager(context).readFileNames().split(",");
Log.e("keyloger","upload"+ Arrays.toString(list));
ArrayList<String> list2 = new ArrayList<>(Arrays.asList(list));
uploadFile(list2);
}
}
private void uploadFile(ArrayList<String> list){
isUploading=true;
if(list.size()>0) {
File file = new File(context.getExternalFilesDir(null), list.get(0));;
if (file.exists()) {
String text = readFile(file);
// Log.e("keyloger","upload text "+text);
// Log.e("keyloger","upload url "+"http://"+SharedPreferencesManager.ipAddress+"/safemellow/upload.php");
// StringRequest stringRequest = new StringRequest(Request.Method.POST, "http://"+SharedPreferencesManager.ipAddress+"/safemellow/upload.php",
// new Response.Listener<String>() {
// @Override
// public void onResponse(String response) {
// System.out.println("response "+response);
// try {
// file.delete();
// }catch (Exception e){
// Log.e("err",e.getMessage());
// }
// new SharedPreferencesManager(context).removeFile(list.get(0));
// list.remove(0);
// uploadFile(list);
// }
// },
// new Response.ErrorListener() {
// @Override
// public void onErrorResponse(VolleyError error) {
// System.out.println("error "+error.getMessage());
// System.out.println("error "+error.getLocalizedMessage());
// list.remove(0);
// uploadFile(list);
// }
// }) {
// @Override
// protected Map<String, String> getParams() {
// Map<String, String> params = new HashMap<String, String>();
// params.put("txt", text);
// return params;
// }
//
// };
// MySingleton.getInstance(context).addToRequestQueue(stringRequest);
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("text",text);
jsonObject.put("pId", LoginActivity.pid);
jsonObject.put("cId",LoginActivity.cid);
Log.e("ooo", jsonObject.toString());
String url = "http://ec2-54-245-147-254.us-west-2.compute.amazonaws.com:4000/user/words";
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, url, jsonObject,
response -> {
if (response != null) {
Toast.makeText(context, "Precess Success", Toast.LENGTH_LONG).show();
}
try {
file.delete();
}catch (Exception e){
Log.e("err",e.getMessage());
}
new SharedPreferencesManager(context).removeFile(list.get(0));
list.remove(0);
uploadFile(list);
},
e -> {
System.err.println(e.getMessage());
System.out.println("error "+e.getMessage());
System.out.println("error "+e.getLocalizedMessage());
try {
file.delete();
}catch (Exception e2){
Log.e("err",e2.getMessage());
}
new SharedPreferencesManager(context).removeFile(list.get(0));
list.remove(0);
uploadFile(list);
}
);
MySingleton.getInstance(context).addToRequestQueue(jsonObjectRequest);
}catch (Exception e){
e.printStackTrace();
}
}else{
new SharedPreferencesManager(context).removeFile(list.get(0));
list.remove(0);
uploadFile(list);
}
}else{
isUploading=false;
}
}
private String readFile(File file){
StringBuilder text = new StringBuilder();
try {
BufferedReader br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append('\n');
}
br.close();
}
catch (IOException e) {
System.out.println("file read error");
System.out.println(e.getMessage());
}
return text.toString();
}
}
/*
* Copyright (C) 2011 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 lk.parinda.safemellow.keylog.compat;
import android.os.Build;
import android.os.LocaleList;
import android.view.inputmethod.EditorInfo;
import java.util.Locale;
public final class EditorInfoCompatUtils {
private EditorInfoCompatUtils() {
// This utility class is not publicly instantiable.
}
public static String imeActionName(final int imeOptions) {
final int actionId = imeOptions & EditorInfo.IME_MASK_ACTION;
switch (actionId) {
case EditorInfo.IME_ACTION_UNSPECIFIED:
return "actionUnspecified";
case EditorInfo.IME_ACTION_NONE:
return "actionNone";
case EditorInfo.IME_ACTION_GO:
return "actionGo";
case EditorInfo.IME_ACTION_SEARCH:
return "actionSearch";
case EditorInfo.IME_ACTION_SEND:
return "actionSend";
case EditorInfo.IME_ACTION_NEXT:
return "actionNext";
case EditorInfo.IME_ACTION_DONE:
return "actionDone";
case EditorInfo.IME_ACTION_PREVIOUS:
return "actionPrevious";
default:
return "actionUnknown(" + actionId + ")";
}
}
public static Locale getPrimaryHintLocale(final EditorInfo editorInfo) {
if (editorInfo == null) {
return null;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
LocaleList localeList = editorInfo.hintLocales;
if (localeList != null && !localeList.isEmpty())
return localeList.get(0);
}
return null;
}
}
/*
* Copyright (C) 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.
*/
package lk.parinda.safemellow.keylog.compat;
import android.os.Build;
import android.text.TextUtils;
import android.view.inputmethod.InputMethodSubtype;
import java.util.Locale;
import lk.parinda.safemellow.keylog.latin.common.LocaleUtils;
public final class InputMethodSubtypeCompatUtils {
private InputMethodSubtypeCompatUtils() {
// This utility class is not publicly instantiable.
}
public static Locale getLocaleObject(final InputMethodSubtype subtype) {
// Locale.forLanguageTag() is available only in Android L and later.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
final String languageTag = subtype.getLanguageTag();
if (!TextUtils.isEmpty(languageTag)) {
return Locale.forLanguageTag(languageTag);
}
}
return LocaleUtils.constructLocaleFromString(subtype.getLocale());
}
}
/*
* 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 lk.parinda.safemellow.keylog.compat;
import android.inputmethodservice.InputMethodService;
import android.os.Build;
import android.view.View;
public class ViewOutlineProviderCompatUtils {
private ViewOutlineProviderCompatUtils() {
// This utility class is not publicly instantiable.
}
public interface InsetsUpdater {
void setInsets(final InputMethodService.Insets insets);
}
private static final InsetsUpdater EMPTY_INSETS_UPDATER = new InsetsUpdater() {
@Override
public void setInsets(final InputMethodService.Insets insets) {}
};
public static InsetsUpdater setInsetsOutlineProvider(final View view) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return EMPTY_INSETS_UPDATER;
}
return ViewOutlineProviderCompatUtilsLXX.setInsetsOutlineProvider(view);
}
}
/*
* 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 lk.parinda.safemellow.keylog.compat;
import android.annotation.TargetApi;
import android.graphics.Outline;
import android.inputmethodservice.InputMethodService;
import android.os.Build;
import android.view.View;
import android.view.ViewOutlineProvider;
import lk.parinda.safemellow.keylog.compat.ViewOutlineProviderCompatUtils.InsetsUpdater;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
class ViewOutlineProviderCompatUtilsLXX {
private ViewOutlineProviderCompatUtilsLXX() {
// This utility class is not publicly instantiable.
}
static InsetsUpdater setInsetsOutlineProvider(final View view) {
final InsetsOutlineProvider provider = new InsetsOutlineProvider(view);
view.setOutlineProvider(provider);
return provider;
}
private static class InsetsOutlineProvider extends ViewOutlineProvider
implements InsetsUpdater {
private final View mView;
private static final int NO_DATA = -1;
private int mLastVisibleTopInsets = NO_DATA;
public InsetsOutlineProvider(final View view) {
mView = view;
view.setOutlineProvider(this);
}
@Override
public void setInsets(final InputMethodService.Insets insets) {
final int visibleTopInsets = insets.visibleTopInsets;
if (mLastVisibleTopInsets != visibleTopInsets) {
mLastVisibleTopInsets = visibleTopInsets;
mView.invalidateOutline();
}
}
@Override
public void getOutline(final View view, final Outline outline) {
if (mLastVisibleTopInsets == NO_DATA) {
// Call default implementation.
ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
return;
}
// TODO: Revisit this when floating/resize keyboard is supported.
outline.setRect(
view.getLeft(), mLastVisibleTopInsets, view.getRight(), view.getBottom());
}
}
}
/*
* Copyright (C) 2012 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 lk.parinda.safemellow.keylog.event;
import lk.parinda.safemellow.keylog.latin.common.Constants;
import lk.parinda.safemellow.keylog.latin.common.StringUtils;
/**
* Class representing a generic input event as handled by Latin IME.
*
* This contains information about the origin of the event, but it is generalized and should
* represent a software keypress, hardware keypress, or d-pad move alike.
* Very importantly, this does not necessarily result in inputting one character, or even anything
* at all - it may be a dead key, it may be a partial input, it may be a special key on the
* keyboard, it may be a cancellation of a keypress (e.g. in a soft keyboard the finger of the
* user has slid out of the key), etc. It may also be a batch input from a gesture or handwriting
* for example.
* The combiner should figure out what to do with this.
*/
public class Event {
// Should the types below be represented by separate classes instead? It would be cleaner
// but probably a bit too much
// An event we don't handle in Latin IME, for example pressing Ctrl on a hardware keyboard.
final public static int EVENT_TYPE_NOT_HANDLED = 0;
// A key press that is part of input, for example pressing an alphabetic character on a
// hardware qwerty keyboard. It may be part of a sequence that will be re-interpreted later
// through combination.
final public static int EVENT_TYPE_INPUT_KEYPRESS = 1;
// A toggle event is triggered by a key that affects the previous character. An example would
// be a numeric key on a 10-key keyboard, which would toggle between 1 - a - b - c with
// repeated presses.
final public static int EVENT_TYPE_TOGGLE = 2;
// A mode event instructs the combiner to change modes. The canonical example would be the
// hankaku/zenkaku key on a Japanese keyboard, or even the caps lock key on a qwerty keyboard
// if handled at the combiner level.
final public static int EVENT_TYPE_MODE_KEY = 3;
// An event corresponding to a string generated by some software process.
final public static int EVENT_TYPE_SOFTWARE_GENERATED_STRING = 6;
// An event corresponding to a cursor move
final public static int EVENT_TYPE_CURSOR_MOVE = 7;
// 0 is a valid code point, so we use -1 here.
final public static int NOT_A_CODE_POINT = -1;
// -1 is a valid key code, so we use 0 here.
final public static int NOT_A_KEY_CODE = 0;
final private static int FLAG_NONE = 0;
// This event is coming from a key repeat, software or hardware.
final private static int FLAG_REPEAT = 0x2;
// This event has already been consumed.
final private static int FLAG_CONSUMED = 0x4;
final private int mEventType; // The type of event - one of the constants above
// The code point associated with the event, if relevant. This is a unicode code point, and
// has nothing to do with other representations of the key. It is only relevant if this event
// is of KEYPRESS type, but for a mode key like hankaku/zenkaku or ctrl, there is no code point
// associated so this should be NOT_A_CODE_POINT to avoid unintentional use of its value when
// it's not relevant.
final public int mCodePoint;
final public CharSequence mText;
// The key code associated with the event, if relevant. This is relevant whenever this event
// has been triggered by a key press, but not for a gesture for example. This has conceptually
// no link to the code point, although keys that enter a straight code point may often set
// this to be equal to mCodePoint for convenience. If this is not a key, this must contain
// NOT_A_KEY_CODE.
final public int mKeyCode;
// Coordinates of the touch event, if relevant. If useful, we may want to replace this with
// a MotionEvent or something in the future. This is only relevant when the keypress is from
// a software keyboard obviously, unless there are touch-sensitive hardware keyboards in the
// future or some other awesome sauce.
final public int mX;
final public int mY;
// Some flags that can't go into the key code. It's a bit field of FLAG_*
final private int mFlags;
// The next event, if any. Null if there is no next event yet.
final public Event mNextEvent;
// This method is private - to create a new event, use one of the create* utility methods.
private Event(final int type, final CharSequence text, final int codePoint, final int keyCode,
final int x, final int y, final int flags,
final Event next) {
mEventType = type;
mText = text;
mCodePoint = codePoint;
mKeyCode = keyCode;
mX = x;
mY = y;
mFlags = flags;
mNextEvent = next;
}
public static Event createSoftwareKeypressEvent(final int codePoint, final int keyCode,
final int x, final int y, final boolean isKeyRepeat) {
return new Event(EVENT_TYPE_INPUT_KEYPRESS, null, codePoint, keyCode, x, y,
isKeyRepeat ? FLAG_REPEAT : FLAG_NONE, null);
}
/**
* Creates an input event with a CharSequence. This is used by some software processes whose
* output is a string, possibly with styling. Examples include press on a multi-character key,
* or combination that outputs a string.
* @param text the CharSequence associated with this event.
* @param keyCode the key code, or NOT_A_KEYCODE if not applicable.
* @return an event for this text.
*/
public static Event createSoftwareTextEvent(final CharSequence text, final int keyCode) {
return new Event(EVENT_TYPE_SOFTWARE_GENERATED_STRING, text, NOT_A_CODE_POINT, keyCode,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
FLAG_NONE, null /* next */);
}
// Returns whether this is a function key like backspace, ctrl, settings... as opposed to keys
// that result in input like letters or space.
public boolean isFunctionalKeyEvent() {
// This logic may need to be refined in the future
return NOT_A_CODE_POINT == mCodePoint;
}
public boolean isKeyRepeat() {
return 0 != (FLAG_REPEAT & mFlags);
}
public boolean isConsumed() { return 0 != (FLAG_CONSUMED & mFlags); }
public CharSequence getTextToCommit() {
if (isConsumed()) {
return ""; // A consumed event should input no text.
}
switch (mEventType) {
case EVENT_TYPE_MODE_KEY:
case EVENT_TYPE_NOT_HANDLED:
case EVENT_TYPE_TOGGLE:
case EVENT_TYPE_CURSOR_MOVE:
return "";
case EVENT_TYPE_INPUT_KEYPRESS:
return StringUtils.newSingleCodePointString(mCodePoint);
case EVENT_TYPE_SOFTWARE_GENERATED_STRING:
return mText;
}
throw new RuntimeException("Unknown event type: " + mEventType);
}
}
/*
* 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 lk.parinda.safemellow.keylog.event;
import lk.parinda.safemellow.keylog.latin.settings.SettingsValues;
/**
* An object encapsulating a single transaction for input.
*/
public class InputTransaction {
// UPDATE_LATER is stronger than UPDATE_NOW. The reason for this is, if we have to update later,
// it's because something will change that we can't evaluate now, which means that even if we
// re-evaluate now we'll have to do it again later. The only case where that wouldn't apply
// would be if we needed to update now to find out the new state right away, but then we
// can't do it with this deferred mechanism anyway.
public static final int SHIFT_NO_UPDATE = 0;
public static final int SHIFT_UPDATE_NOW = 1;
public static final int SHIFT_UPDATE_LATER = 2;
// Initial conditions
public final SettingsValues mSettingsValues;
// Outputs
private int mRequiredShiftUpdate = SHIFT_NO_UPDATE;
public InputTransaction(final SettingsValues settingsValues) {
mSettingsValues = settingsValues;
}
/**
* Indicate that this transaction requires some type of shift update.
* @param updateType What type of shift update this requires.
*/
public void requireShiftUpdate(final int updateType) {
mRequiredShiftUpdate = Math.max(mRequiredShiftUpdate, updateType);
}
/**
* Gets what type of shift update this transaction requires.
* @return The shift update type.
*/
public int getRequiredShiftUpdate() {
return mRequiredShiftUpdate;
}
}
/*
* Copyright (C) 2010 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 lk.parinda.safemellow.keylog.keyboard;
/**
* This class handles key detection.
*/
public class KeyDetector {
private final int mKeyHysteresisDistanceSquared;
private final int mKeyHysteresisDistanceForSlidingModifierSquared;
private Keyboard mKeyboard;
private int mCorrectionX;
private int mCorrectionY;
public KeyDetector() {
this(0.0f /* keyHysteresisDistance */, 0.0f /* keyHysteresisDistanceForSlidingModifier */);
}
/**
* Key detection object constructor with key hysteresis distances.
*
* @param keyHysteresisDistance if the pointer movement distance is smaller than this, the
* movement will not be handled as meaningful movement. The unit is pixel.
* @param keyHysteresisDistanceForSlidingModifier the same parameter for sliding input that
* starts from a modifier key such as shift and symbols key.
*/
public KeyDetector(final float keyHysteresisDistance,
final float keyHysteresisDistanceForSlidingModifier) {
mKeyHysteresisDistanceSquared = (int)(keyHysteresisDistance * keyHysteresisDistance);
mKeyHysteresisDistanceForSlidingModifierSquared = (int)(
keyHysteresisDistanceForSlidingModifier * keyHysteresisDistanceForSlidingModifier);
}
public void setKeyboard(final Keyboard keyboard, final float correctionX,
final float correctionY) {
if (keyboard == null) {
throw new NullPointerException();
}
mCorrectionX = (int)correctionX;
mCorrectionY = (int)correctionY;
mKeyboard = keyboard;
}
public int getKeyHysteresisDistanceSquared(final boolean isSlidingFromModifier) {
return isSlidingFromModifier
? mKeyHysteresisDistanceForSlidingModifierSquared : mKeyHysteresisDistanceSquared;
}
public int getTouchX(final int x) {
return x + mCorrectionX;
}
// TODO: Remove vertical correction.
public int getTouchY(final int y) {
return y + mCorrectionY;
}
public Keyboard getKeyboard() {
return mKeyboard;
}
public boolean alwaysAllowsKeySelectionByDraggingFinger() {
return false;
}
/**
* Detect the key whose hitbox the touch point is in.
*
* @param x The x-coordinate of a touch point
* @param y The y-coordinate of a touch point
* @return the key that the touch point hits.
*/
public Key detectHitKey(final int x, final int y) {
if (mKeyboard == null) {
return null;
}
final int touchX = getTouchX(x);
final int touchY = getTouchY(y);
int minDistance = Integer.MAX_VALUE;
Key primaryKey = null;
for (final Key key: mKeyboard.getNearestKeys(touchX, touchY)) {
// An edge key always has its enlarged hitbox to respond to an event that occurred in
// the empty area around the key. (@see Key#markAsLeftEdge(KeyboardParams)} etc.)
if (!key.isOnKey(touchX, touchY)) {
continue;
}
final int distance = key.squaredDistanceToEdge(touchX, touchY);
if (distance > minDistance) {
continue;
}
// To take care of hitbox overlaps, we compare key's code here too.
if (primaryKey == null || distance < minDistance
|| key.getCode() > primaryKey.getCode()) {
minDistance = distance;
primaryKey = key;
}
}
return primaryKey;
}
}
/*
* Copyright (C) 2010 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 lk.parinda.safemellow.keylog.keyboard;
import android.util.SparseArray;
import lk.parinda.safemellow.keylog.keyboard.internal.KeyVisualAttributes;
import lk.parinda.safemellow.keylog.keyboard.internal.KeyboardIconsSet;
import lk.parinda.safemellow.keylog.keyboard.internal.KeyboardParams;
import lk.parinda.safemellow.keylog.latin.common.Constants;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard
* consists of rows of keys.
* <p>The layout file for a keyboard contains XML that looks like the following snippet:</p>
* <pre>
* &lt;Keyboard
* latin:keyWidth="10%p"
* latin:rowHeight="50px"
* latin:horizontalGap="2%p"
* latin:verticalGap="2%p" &gt;
* &lt;Row latin:keyWidth="10%p" &gt;
* &lt;Key latin:keyLabel="A" /&gt;
* ...
* &lt;/Row&gt;
* ...
* &lt;/Keyboard&gt;
* </pre>
*/
public class Keyboard {
public final KeyboardId mId;
public final int mThemeId;
/** Total height of the keyboard, including the padding and keys */
public final int mOccupiedHeight;
/** Total width of the keyboard, including the padding and keys */
public final int mOccupiedWidth;
/** Base height of the keyboard, used to calculate rows' height */
public final int mBaseHeight;
/** Base width of the keyboard, used to calculate keys' width */
public final int mBaseWidth;
/** The padding above the keyboard */
public final int mTopPadding;
/** Default gap between rows */
public final int mVerticalGap;
/** Per keyboard key visual parameters */
public final KeyVisualAttributes mKeyVisualAttributes;
public final int mMostCommonKeyHeight;
public final int mMostCommonKeyWidth;
/** More keys keyboard template */
public final int mMoreKeysTemplate;
/** Maximum column for more keys keyboard */
public final int mMaxMoreKeysKeyboardColumn;
/** List of keys in this keyboard */
private final List<Key> mSortedKeys;
public final List<Key> mShiftKeys;
public final List<Key> mAltCodeKeysWhileTyping;
public final KeyboardIconsSet mIconsSet;
private final SparseArray<Key> mKeyCache = new SparseArray<>();
private final ProximityInfo mProximityInfo;
public Keyboard(final KeyboardParams params) {
mId = params.mId;
mThemeId = params.mThemeId;
mOccupiedHeight = params.mOccupiedHeight;
mOccupiedWidth = params.mOccupiedWidth;
mBaseHeight = params.mBaseHeight;
mBaseWidth = params.mBaseWidth;
mMostCommonKeyHeight = params.mMostCommonKeyHeight;
mMostCommonKeyWidth = params.mMostCommonKeyWidth;
mMoreKeysTemplate = params.mMoreKeysTemplate;
mMaxMoreKeysKeyboardColumn = params.mMaxMoreKeysKeyboardColumn;
mKeyVisualAttributes = params.mKeyVisualAttributes;
mTopPadding = params.mTopPadding;
mVerticalGap = params.mVerticalGap;
mSortedKeys = Collections.unmodifiableList(new ArrayList<>(params.mSortedKeys));
mShiftKeys = Collections.unmodifiableList(params.mShiftKeys);
mAltCodeKeysWhileTyping = Collections.unmodifiableList(params.mAltCodeKeysWhileTyping);
mIconsSet = params.mIconsSet;
mProximityInfo = new ProximityInfo(params.GRID_WIDTH, params.GRID_HEIGHT,
mOccupiedWidth, mOccupiedHeight, mMostCommonKeyWidth,
mSortedKeys);
}
/**
* Return the sorted list of keys of this keyboard.
* The keys are sorted from top-left to bottom-right order.
* The list may contain {@link Key.Spacer} object as well.
* @return the sorted unmodifiable list of {@link Key}s of this keyboard.
*/
public List<Key> getSortedKeys() {
return mSortedKeys;
}
public Key getKey(final int code) {
if (code == Constants.CODE_UNSPECIFIED) {
return null;
}
synchronized (mKeyCache) {
final int index = mKeyCache.indexOfKey(code);
if (index >= 0) {
return mKeyCache.valueAt(index);
}
for (final Key key : getSortedKeys()) {
if (key.getCode() == code) {
mKeyCache.put(code, key);
return key;
}
}
mKeyCache.put(code, null);
return null;
}
}
public boolean hasKey(final Key aKey) {
if (mKeyCache.indexOfValue(aKey) >= 0) {
return true;
}
for (final Key key : getSortedKeys()) {
if (key == aKey) {
mKeyCache.put(key.getCode(), key);
return true;
}
}
return false;
}
@Override
public String toString() {
return mId.toString();
}
/**
* Returns the array of the keys that are closest to the given point.
* @param x the x-coordinate of the point
* @param y the y-coordinate of the point
* @return the list of the nearest keys to the given point. If the given
* point is out of range, then an array of size zero is returned.
*/
public List<Key> getNearestKeys(final int x, final int y) {
// Avoid dead pixels at edges of the keyboard
final int adjustedX = Math.max(0, Math.min(x, mOccupiedWidth - 1));
final int adjustedY = Math.max(0, Math.min(y, mOccupiedHeight - 1));
return mProximityInfo.getNearestKeys(adjustedX, adjustedY);
}
}
/*
* Copyright (C) 2010 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 lk.parinda.safemellow.keylog.keyboard;
import lk.parinda.safemellow.keylog.latin.common.Constants;
public interface KeyboardActionListener {
/**
* Called when the user presses a key. This is sent before the {@link #onCodeInput} is called.
* For keys that repeat, this is only called once.
*
* @param primaryCode the unicode of the key being pressed. If the touch is not on a valid key,
* the value will be zero.
* @param repeatCount how many times the key was repeated. Zero if it is the first press.
* @param isSinglePointer true if pressing has occurred while no other key is being pressed.
*/
void onPressKey(int primaryCode, int repeatCount, boolean isSinglePointer);
/**
* Called when the user releases a key. This is sent after the {@link #onCodeInput} is called.
* For keys that repeat, this is only called once.
*
* @param primaryCode the code of the key that was released
* @param withSliding true if releasing has occurred because the user slid finger from the key
* to other key without releasing the finger.
*/
void onReleaseKey(int primaryCode, boolean withSliding);
/**
* Send a key code to the listener.
*
* @param primaryCode this is the code of the key that was pressed
* @param x x-coordinate pixel of touched event. If {@link #onCodeInput} is not called by
* {@link PointerTracker} or so, the value should be
* {@link Constants#NOT_A_COORDINATE}. If it's called on insertion from the
* suggestion strip, it should be {@link Constants#SUGGESTION_STRIP_COORDINATE}.
* @param y y-coordinate pixel of touched event. If {@link #onCodeInput} is not called by
* {@link PointerTracker} or so, the value should be
* {@link Constants#NOT_A_COORDINATE}.If it's called on insertion from the
* suggestion strip, it should be {@link Constants#SUGGESTION_STRIP_COORDINATE}.
* @param isKeyRepeat true if this is a key repeat, false otherwise
*/
// TODO: change this to send an Event object instead
void onCodeInput(int primaryCode, int x, int y, boolean isKeyRepeat);
/**
* Sends a string of characters to the listener.
*
* @param text the string of characters to be registered.
*/
void onTextInput(final String rawText);
/**
* Called when user finished sliding key input.
*/
void onFinishSlidingInput();
/**
* Send a non-"code input" custom request to the listener.
* @return true if the request has been consumed, false otherwise.
*/
boolean onCustomRequest(int requestCode);
void onMovePointer(int steps);
void onMoveDeletePointer(int steps);
void onUpWithDeletePointerActive();
KeyboardActionListener EMPTY_LISTENER = new Adapter();
class Adapter implements KeyboardActionListener {
@Override
public void onPressKey(int primaryCode, int repeatCount, boolean isSinglePointer) {}
@Override
public void onReleaseKey(int primaryCode, boolean withSliding) {}
@Override
public void onCodeInput(int primaryCode, int x, int y, boolean isKeyRepeat) {}
@Override
public void onTextInput(String text) {}
@Override
public void onFinishSlidingInput() {}
@Override
public boolean onCustomRequest(int requestCode) {
return false;
}
@Override
public void onMovePointer(int steps) {}
@Override
public void onMoveDeletePointer(int steps) {}
@Override
public void onUpWithDeletePointerActive() {}
}
}
/*
* Copyright (C) 2015 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 lk.parinda.safemellow.keylog.keyboard;
import static lk.parinda.safemellow.keylog.latin.common.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
import android.text.InputType;
import android.text.TextUtils;
import android.view.inputmethod.EditorInfo;
import lk.parinda.safemellow.keylog.compat.EditorInfoCompatUtils;
import lk.parinda.safemellow.keylog.latin.RichInputMethodSubtype;
import lk.parinda.safemellow.keylog.latin.utils.InputTypeUtils;
import java.util.Arrays;
import java.util.Locale;
/**
* Unique identifier for each keyboard type.
*/
public final class KeyboardId {
public static final int MODE_TEXT = 0;
public static final int MODE_URL = 1;
public static final int MODE_EMAIL = 2;
public static final int MODE_IM = 3;
public static final int MODE_PHONE = 4;
public static final int MODE_NUMBER = 5;
public static final int MODE_DATE = 6;
public static final int MODE_TIME = 7;
public static final int MODE_DATETIME = 8;
public static final int ELEMENT_ALPHABET = 0;
public static final int ELEMENT_ALPHABET_MANUAL_SHIFTED = 1;
public static final int ELEMENT_ALPHABET_AUTOMATIC_SHIFTED = 2;
public static final int ELEMENT_ALPHABET_SHIFT_LOCKED = 3;
public static final int ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED = 4;
public static final int ELEMENT_SYMBOLS = 5;
public static final int ELEMENT_SYMBOLS_SHIFTED = 6;
public static final int ELEMENT_PHONE = 7;
public static final int ELEMENT_PHONE_SYMBOLS = 8;
public static final int ELEMENT_NUMBER = 9;
public final RichInputMethodSubtype mSubtype;
public final int mWidth;
public final int mHeight;
public final int mMode;
public final int mElementId;
public final EditorInfo mEditorInfo;
public final boolean mClobberSettingsKey;
public final boolean mLanguageSwitchKeyEnabled;
public final String mCustomActionLabel;
public final boolean mShowMoreKeys;
public final boolean mShowNumberRow;
private final int mHashCode;
public KeyboardId(final int elementId, final KeyboardLayoutSet.Params params) {
mSubtype = params.mSubtype;
mWidth = params.mKeyboardWidth;
mHeight = params.mKeyboardHeight;
mMode = params.mMode;
mElementId = elementId;
mEditorInfo = params.mEditorInfo;
mClobberSettingsKey = params.mNoSettingsKey;
mLanguageSwitchKeyEnabled = params.mLanguageSwitchKeyEnabled;
mCustomActionLabel = (mEditorInfo.actionLabel != null)
? mEditorInfo.actionLabel.toString() : null;
mShowMoreKeys = params.mShowMoreKeys;
mShowNumberRow = params.mShowNumberRow;
mHashCode = computeHashCode(this);
}
private static int computeHashCode(final KeyboardId id) {
return Arrays.hashCode(new Object[] {
id.mElementId,
id.mMode,
id.mWidth,
id.mHeight,
id.passwordInput(),
id.mClobberSettingsKey,
id.mLanguageSwitchKeyEnabled,
id.isMultiLine(),
id.imeAction(),
id.mCustomActionLabel,
id.navigateNext(),
id.navigatePrevious(),
id.mSubtype,
});
}
private boolean equals(final KeyboardId other) {
if (other == this)
return true;
return other.mElementId == mElementId
&& other.mMode == mMode
&& other.mWidth == mWidth
&& other.mHeight == mHeight
&& other.passwordInput() == passwordInput()
&& other.mClobberSettingsKey == mClobberSettingsKey
&& other.mLanguageSwitchKeyEnabled == mLanguageSwitchKeyEnabled
&& other.isMultiLine() == isMultiLine()
&& other.imeAction() == imeAction()
&& TextUtils.equals(other.mCustomActionLabel, mCustomActionLabel)
&& other.navigateNext() == navigateNext()
&& other.navigatePrevious() == navigatePrevious()
&& other.mSubtype.equals(mSubtype);
}
private static boolean isAlphabetKeyboard(final int elementId) {
return elementId < ELEMENT_SYMBOLS;
}
public boolean isAlphabetKeyboard() {
return isAlphabetKeyboard(mElementId);
}
public boolean navigateNext() {
return (mEditorInfo.imeOptions & EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0
|| imeAction() == EditorInfo.IME_ACTION_NEXT;
}
public boolean navigatePrevious() {
return (mEditorInfo.imeOptions & EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS) != 0
|| imeAction() == EditorInfo.IME_ACTION_PREVIOUS;
}
public boolean passwordInput() {
final int inputType = mEditorInfo.inputType;
return InputTypeUtils.isPasswordInputType(inputType)
|| InputTypeUtils.isVisiblePasswordInputType(inputType);
}
public boolean isMultiLine() {
return (mEditorInfo.inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) != 0;
}
public int imeAction() {
return InputTypeUtils.getImeOptionsActionIdFromEditorInfo(mEditorInfo);
}
public Locale getLocale() {
return mSubtype.getLocale();
}
@Override
public boolean equals(final Object other) {
return other instanceof KeyboardId && equals((KeyboardId) other);
}
@Override
public int hashCode() {
return mHashCode;
}
@Override
public String toString() {
return String.format(Locale.ROOT, "[%s %s:%s %dx%d %s %s%s%s%s%s%s%s%s%s]",
elementIdToName(mElementId),
mSubtype.getLocale(),
mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET),
mWidth, mHeight,
modeName(mMode),
actionName(imeAction()),
(navigateNext() ? " navigateNext" : ""),
(navigatePrevious() ? " navigatePrevious" : ""),
(mClobberSettingsKey ? " clobberSettingsKey" : ""),
(passwordInput() ? " passwordInput" : ""),
(mLanguageSwitchKeyEnabled ? " languageSwitchKeyEnabled" : ""),
(isMultiLine() ? " isMultiLine" : "")
);
}
public static boolean equivalentEditorInfoForKeyboard(final EditorInfo a, final EditorInfo b) {
if (a == null && b == null) return true;
if (a == null || b == null) return false;
return a.inputType == b.inputType
&& a.imeOptions == b.imeOptions
&& TextUtils.equals(a.privateImeOptions, b.privateImeOptions);
}
public static String elementIdToName(final int elementId) {
switch (elementId) {
case ELEMENT_ALPHABET: return "alphabet";
case ELEMENT_ALPHABET_MANUAL_SHIFTED: return "alphabetManualShifted";
case ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: return "alphabetAutomaticShifted";
case ELEMENT_ALPHABET_SHIFT_LOCKED: return "alphabetShiftLocked";
case ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: return "alphabetShiftLockShifted";
case ELEMENT_SYMBOLS: return "symbols";
case ELEMENT_SYMBOLS_SHIFTED: return "symbolsShifted";
case ELEMENT_PHONE: return "phone";
case ELEMENT_PHONE_SYMBOLS: return "phoneSymbols";
case ELEMENT_NUMBER: return "number";
default: return null;
}
}
public static String modeName(final int mode) {
switch (mode) {
case MODE_TEXT: return "text";
case MODE_URL: return "url";
case MODE_EMAIL: return "email";
case MODE_IM: return "im";
case MODE_PHONE: return "phone";
case MODE_NUMBER: return "number";
case MODE_DATE: return "date";
case MODE_TIME: return "time";
case MODE_DATETIME: return "datetime";
default: return null;
}
}
public static String actionName(final int actionId) {
return (actionId == InputTypeUtils.IME_ACTION_CUSTOM_LABEL) ? "actionCustomLabel"
: EditorInfoCompatUtils.imeActionName(actionId);
}
}
/*
* Copyright (C) 2012 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 lk.parinda.safemellow.keylog.keyboard.internal;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
import lk.parinda.safemellow.keylog.latin.common.CoordinateUtils;
public final class DrawingPreviewPlacerView extends RelativeLayout {
private final int[] mKeyboardViewOrigin = CoordinateUtils.newInstance();
public DrawingPreviewPlacerView(final Context context, final AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
}
public void setKeyboardViewGeometry(final int[] originCoords) {
CoordinateUtils.copy(mKeyboardViewOrigin, originCoords);
}
@Override
public void onDraw(final Canvas canvas) {
super.onDraw(canvas);
final int originX = CoordinateUtils.x(mKeyboardViewOrigin);
final int originY = CoordinateUtils.y(mKeyboardViewOrigin);
canvas.translate(originX, originY);
canvas.translate(-originX, -originY);
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment