Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • isanga/securitycam
1 result
Show changes
Commits on Source (27)
Showing
with 1569 additions and 25 deletions
SecurityCam
\ No newline at end of file
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<DBN-PSQL>
<case-options enabled="true">
<option name="KEYWORD_CASE" value="lower" />
<option name="FUNCTION_CASE" value="lower" />
<option name="PARAMETER_CASE" value="lower" />
<option name="DATATYPE_CASE" value="lower" />
<option name="OBJECT_CASE" value="preserve" />
</case-options>
<formatting-settings enabled="false" />
</DBN-PSQL>
<DBN-SQL>
<case-options enabled="true">
<option name="KEYWORD_CASE" value="lower" />
<option name="FUNCTION_CASE" value="lower" />
<option name="PARAMETER_CASE" value="lower" />
<option name="DATATYPE_CASE" value="lower" />
<option name="OBJECT_CASE" value="preserve" />
</case-options>
<formatting-settings enabled="false">
<option name="STATEMENT_SPACING" value="one_line" />
<option name="CLAUSE_CHOP_DOWN" value="chop_down_if_statement_long" />
<option name="ITERATION_ELEMENTS_WRAPPING" value="chop_down_if_not_single" />
</formatting-settings>
</DBN-SQL>
<codeStyleSettings language="XML">
<arrangement>
<rules>
......
This diff is collapsed.
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 29
......@@ -23,7 +24,15 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'com.google.firebase:firebase-auth:16.0.5'
implementation 'com.google.firebase:firebase-storage:16.0.5'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
implementation 'com.google.android.gms:play-services-auth:17.0.0'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'com.github.bumptech.glide:glide:4.10.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'
}
{
"project_info": {
"project_number": "152764582545",
"firebase_url": "https://securitycam-abc57.firebaseio.com",
"project_id": "securitycam-abc57",
"storage_bucket": "securitycam-abc57.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:152764582545:android:62626b79604fc542108d30",
"android_client_info": {
"package_name": "com.isanga.securitycam"
}
},
"oauth_client": [
{
"client_id": "152764582545-jethj179b4c3b991tggk1b2ogq0qagf2.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "com.isanga.securitycam",
"certificate_hash": "8678c1ba23f408b62c6f4744fc7c99c10712dd40"
}
},
{
"client_id": "152764582545-4qfuhv353vfcc1de8bocoqn7de6jpnsp.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "com.isanga.securitycam",
"certificate_hash": "85592b9cfe9d3e89490072f43f27742c8a5bc679"
}
},
{
"client_id": "152764582545-rhhgsf7nf1fp9ieptjq51cvo5oot4p0d.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyA5iPUqZEAAd8BUsfF2LES6N4SzmQftaO0"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "152764582545-rhhgsf7nf1fp9ieptjq51cvo5oot4p0d.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}
\ No newline at end of file
......@@ -2,6 +2,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.isanga.securitycam">
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera2.full" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
......@@ -9,13 +15,22 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<activity android:name=".Activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name=".Models.GenericFileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
</application>
</manifest>
\ No newline at end of file
package com.isanga.securitycam.Activities;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.MenuItem;
import com.google.android.material.navigation.NavigationView;
import com.isanga.securitycam.Fragments.Camera;
import com.isanga.securitycam.Fragments.Clips;
import com.isanga.securitycam.Fragments.Home;
import com.isanga.securitycam.Fragments.User;
import com.isanga.securitycam.R;
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
DrawerLayout drawerLayout; //The menu layout
private static int MY_PERMISSIONS_REQUEST_CAMERA;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Camera permissions.
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.CAMERA)) {
} else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA},
MY_PERMISSIONS_REQUEST_CAMERA);
}
}
//Needed to overwrite the default actionbar
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//Sets up menu click events
NavigationView navigationView = findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(this);
//Initializes menu layout
drawerLayout = findViewById(R.id.menu_drawer);
//Opens Home fragment when app is first opened
if(savedInstanceState==null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, new Home())
.commit();
}
}
//Opens a fragment corresponding to the menu item
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
switch (menuItem.getItemId()){
case R.id.gesture_menu_home:
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, new Home())
.commit();
break;
case R.id.gesture_menu_camera:
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, new Camera())
.commit();
break;
case R.id.gesture_menu_clips:
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, new Clips())
.commit();
break;
case R.id.gesture_menu_user:
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, new User())
.commit();
break;
}
//Closes menu when an item is clicked
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
}
package com.isanga.securitycam.Adapters;
import android.content.Context;
import android.net.Uri;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.isanga.securitycam.Models.ClipsModel;
import com.isanga.securitycam.R;
import java.io.File;
import java.util.ArrayList;
public class ClipsRecyclerViewAdapter extends RecyclerView.Adapter<ClipsRecyclerViewAdapter.ViewHolder> {
private ArrayList<ClipsModel> models;
private LayoutInflater layoutInflater;
private ClipsRecyclerViewListener listener;
private Context context;
public ClipsRecyclerViewAdapter(Context context, ArrayList<ClipsModel> list, ClipsRecyclerViewListener listener){
this.context = context;
this.layoutInflater = LayoutInflater.from(context);
this.models = list;
this.listener = listener;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view= layoutInflater.inflate(R.layout.clip_item_row, parent, false);
return new ViewHolder(view, listener);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
File file = models.get(position).getThumbnail();
Glide.with(context)
.load(Uri.fromFile(file))
.thumbnail(0.1f)
.centerCrop()
.into(holder.clipThumbnail);
}
@Override
public int getItemCount() {
return models.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener,
View.OnCreateContextMenuListener {
ImageView clipThumbnail;
ClipsRecyclerViewListener listener;
public ViewHolder(@NonNull View itemView, ClipsRecyclerViewListener listener) {
super(itemView);
clipThumbnail = itemView.findViewById(R.id.clip_thumbnail);
itemView.setOnClickListener(this);
this.listener = listener;
itemView.setOnCreateContextMenuListener(this);
}
@Override
public void onClick(View v) {
listener.onItemClick(getAdapterPosition());
}
@Override
public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
contextMenu.add(this.getAdapterPosition(), R.id.clip_delete, 0, R.string.clip_delete);
contextMenu.add(this.getAdapterPosition(), R.id.clip_share, 0, R.string.clip_share);
contextMenu.add(this.getAdapterPosition(), R.id.clip_edit, 0, "Edit");
}
}
public interface ClipsRecyclerViewListener{
void onItemClick(int position);
}
}
package com.isanga.securitycam.Fragments;
import android.app.Activity;
import android.content.Context;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import com.isanga.securitycam.R;
import java.util.ArrayList;
import java.util.List;
/**
* A simple {@link Fragment} subclass.
*/
public class Camera extends Fragment {
private static final String TAG = "CameraFragment";
/**
* The camera manager. Used to find the camera.
*/
private CameraManager mCameraManager;
/**
* Handler to use for camera processes. Required by openCamera and createCaptureSession.
* TODO We may need another handler for both processes.
*/
private Handler mHandler;
/**
* The camera device.
*/
private CameraDevice mCameraDevice;
/**
* The id of the camera.
*/
private String mCameraId;
/**
* View used to display the camera preview.
*/
private SurfaceView mSurfaceView;
/**
* The surface view holder.
*/
private SurfaceHolder mSurfaceHolder;
/**
* Implement the logic for surface holder callbacks.
*/
private SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() {
//to avoid constantly opening the camera
boolean secondCall;
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
Log.d(TAG, "Surface created");
mCameraId = null;
secondCall = false;
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
Log.d(TAG, "surfaceChanged");
//Find the back facing camera.
if(mCameraId == null) {
try {
for (String cameraId : mCameraManager.getCameraIdList()) {
if (mCameraManager.getCameraCharacteristics(cameraId).get(mCameraManager.getCameraCharacteristics(cameraId).LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK) {
mCameraId = cameraId;
SurfaceHolder holder = mSurfaceView.getHolder();
DisplayMetrics metrics = new DisplayMetrics();
((Activity)getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics);
holder.setFixedSize(metrics.heightPixels, metrics.widthPixels);
Log.d(TAG, "Found back facing camera");
return;
}
}
} catch (CameraAccessException e) {
Log.d(TAG, "Could not find or access the camera");
}
} else if(secondCall == false) {
try {
mCameraManager.openCamera(mCameraId, mStateCallback, mHandler);
Log.d(TAG, "Camera was opened");
} catch (CameraAccessException e) {
Log.d(TAG, "Could not find or access camera");
} catch (SecurityException e) {
Log.d(TAG, "Found some security exception while opening camera");
}
secondCall = true;
}
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
Log.d(TAG, "Surface destroyed");
surfaceHolder.removeCallback(this);
}
};
/**
* Implementation of callbacks for the camera device.
*/
private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice cameraDevice) {
Log.d(TAG, "Camera onOpened");
List<Surface> surfaceList = new ArrayList<>();
surfaceList.add(mSurfaceView.getHolder().getSurface());
try {
cameraDevice.createCaptureSession(surfaceList, mCaptureSession, mHandler);
} catch(CameraAccessException e) {
}
mCameraDevice = cameraDevice;
}
@Override
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
Log.d(TAG, "Camera onDisconnected");
}
@Override
public void onError(@NonNull CameraDevice cameraDevice, int i) {
Log.d(TAG, "Camera onError");
}
};
/**
* Capture session for our camera device to display the preview on our surface.
*/
CameraCaptureSession mCameraCaptureSession;
/**
* Listener for the session ready/not ready cause the documentation mentions that creating a capture session is an expensive operation.
*/
private CameraCaptureSession.StateCallback mCaptureSession = new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
Log.d(TAG, "Camera configured");
mCameraCaptureSession = cameraCaptureSession;
if(mSurfaceHolder != null) {
try {
CaptureRequest.Builder captureRequest = mCameraDevice.createCaptureRequest(mCameraDevice.TEMPLATE_PREVIEW);
captureRequest.addTarget(mSurfaceHolder.getSurface());
captureRequest.build();
cameraCaptureSession.setRepeatingRequest(captureRequest.build(), null, null);
} catch(CameraAccessException e) {
}
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
Log.d(TAG, "Camera failed configuration");
}
};
/**
* Required empty public constructor.
*/
public Camera() {
}
/**
* {@inheritDoc}
* @param inflater
* @param container
* @param savedInstanceState
* @return
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
mHandler = new Handler();
mCameraManager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);
View layout = inflater.inflate(R.layout.fragment_camera, container, false);
mSurfaceView = layout.findViewById(R.id.camera_surface_view);
mSurfaceView.getHolder().addCallback(mCallback);
mSurfaceHolder = mSurfaceView.getHolder();
return layout;
}
/**
* {@inheritDoc}
*/
@Override
public void onPause() {
super.onPause();
Log.d(TAG, "Camera closed");
if(mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
}
}
}
package com.isanga.securitycam.Fragments;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.core.content.FileProvider;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import com.isanga.securitycam.Adapters.ClipsRecyclerViewAdapter;
import com.isanga.securitycam.Models.ClipsModel;
import com.isanga.securitycam.R;
import java.io.File;
import java.util.ArrayList;
import static androidx.constraintlayout.widget.Constraints.TAG;
/**
* A simple {@link Fragment} subclass.
*/
public class Clips extends Fragment implements ClipsRecyclerViewAdapter.ClipsRecyclerViewListener {
/**
* List to preview clips
*/
private RecyclerView recyclerView;
/**
* Holds a list of clips
*/
private ArrayList<ClipsModel> models;
/**
* Tools needed for recyclerview
*/
private RecyclerView.LayoutManager manager;
private ClipsRecyclerViewAdapter adapter;
/**
* Popup dialog to edit title of clips
*/
private AlertDialog editTitle;
private EditText titleEditor;
/**
* Current id of clip title being edited
*/
private int modelID;
/**
* Media folder
*/
private File folder;
public Clips() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_clips, container, false);
//Get the clips folder
folder = getContext().getExternalFilesDir("media");
//Initializes private variables
editTitle = new AlertDialog.Builder(getContext()).create();
titleEditor = new EditText(getContext());
editTitle.setTitle("Edit title");
editTitle.setView(titleEditor);
//Handles editing titles when SAVE is clicked
editTitle.setButton(DialogInterface.BUTTON_POSITIVE, "SAVE", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String path = folder.getAbsolutePath();
File video = new File(path + "/" + models.get(modelID).getTitle());
String newTitle = titleEditor.getText().toString();
File newVideo = new File(path + "/" + newTitle);
video.renameTo(newVideo);
models.get(modelID).setTitle(newTitle);
}
});
if(savedInstanceState==null) {
setUpRecyclerView(view);
loadThumbnails();
}
//Need to register recyclerview for ContextMenu to work
registerForContextMenu(recyclerView);
return view;
}
/**
* Sets up the recycler view
* @param view
*/
private void setUpRecyclerView(View view){
recyclerView = view.findViewById(R.id.clips_recyclerview);
models = new ArrayList<>();
manager = new GridLayoutManager(getContext(), 3);
recyclerView.setLayoutManager(manager);
adapter = new ClipsRecyclerViewAdapter(getContext(), models, this);
recyclerView.setAdapter(adapter);
}
/**
* Handles click event on items from the list
* @param position position of the item being clicked
*/
@Override
public void onItemClick(int position) {
//If video does not have a default player, prompt apps that support video playing
Intent intent = new Intent(Intent.ACTION_VIEW);
File file = models.get(position).getThumbnail();
//FileProvider is need on sdk targets bigger than 23
Uri uri = FileProvider.getUriForFile(getContext(), getContext().getApplicationContext().getPackageName() + ".provider", file);
intent.setDataAndType(uri, "video/*");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
}
/**
* Handles menu clicks when holding a clip
* @param item
* @return
*/
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.clip_delete:
deleteClip(item.getGroupId());
case R.id.clip_share:
shareClip(item.getGroupId());
case R.id.clip_edit:
editClip(item.getGroupId());
default:
return super.onContextItemSelected(item);
}
}
/**
* Deletes selected clip from the recyclerview and from storage
* @param id
*/
private void deleteClip(int id){
String path = folder.getAbsolutePath() + "/" + models.get(id).getTitle();
File video = new File(path);
video.delete();
models.remove(id);
adapter.notifyDataSetChanged();
Log.d(TAG, "deleteClip: " + path);
}
/**
* Starts an intent to share selected video
* @param id
*/
private void shareClip(int id){
String path = folder.getAbsolutePath() + "/" + models.get(id).getTitle();
File video = new File(path);
Uri uri = FileProvider.getUriForFile(getContext(), getContext().getApplicationContext().getPackageName() + ".provider", video);
Intent intent = new Intent();
intent.setType("video/*");
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(intent, "send"));
}
/**
* Opens up AlertDialog to allow editing title of selected clip
* @param id
*/
private void editClip(int id){
modelID = id;
titleEditor.setText(models.get(id).getTitle());
editTitle.show();
}
/**
* Loads thumbnails from media folder
*/
private void loadThumbnails(){
String path = folder.getAbsolutePath();
Log.d(TAG, "loadThumbnails: " + path);
if(folder.exists()){
File[] videos = folder.listFiles();
if(videos!=null) {
for (File video : videos) {
Log.d(TAG, "currentThumbnail: " + video.getAbsolutePath());
models.add(new ClipsModel(video.getName(), video));
}
}
}
else{
folder.mkdirs();
}
}
}
package com.isanga.securitycam.Fragments;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.isanga.securitycam.R;
/**
* A simple {@link Fragment} subclass.
*/
public class Home extends Fragment {
public Home() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_home, container, false);
}
}
package com.isanga.securitycam.Fragments;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.GoogleAuthProvider;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageMetadata;
import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.UploadTask;
import com.isanga.securitycam.R;
import com.google.android.gms.auth.api.signin.GoogleSignInClient;
import java.io.File;
/**
* A simple {@link Fragment} subclass.
*/
public class User extends Fragment {
/**
* Google authentication handlers
*/
private GoogleSignInClient signInClient;
private FirebaseAuth mAuth;
private static final int RC_SIGN_IN = 9001;
/**
*Buttons and TextView
*/
private TextView username;
private Button signinBtn;
private Button signoutBtn;
private Button syncBtn;
/**
* Current userID
*/
private String userid;
public User() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_user, container, false);
GoogleSignInOptions googleSignInOptions = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.web_client_id))
.requestEmail()
.build();
signInClient = GoogleSignIn.getClient(getContext(), googleSignInOptions);
mAuth = FirebaseAuth.getInstance();
username = view.findViewById(R.id.user_id);
signinBtn = view.findViewById(R.id.user_signinBtn);
signoutBtn = view.findViewById(R.id.user_signoutBtn);
syncBtn = view.findViewById(R.id.user_syncBtn);
/**
* Handles sign in on click
*/
signinBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
signin();
}
});
/**
* Handles sign out on click
*/
signoutBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
signout();
}
});
/**
* Handles sync on click
*/
syncBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
syncFiles();
}
});
checkLoginState();
return view;
}
/**
* Brings up the sign in page for Google accounts
* @param requestCode
* @param resultCode
* @param data
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RC_SIGN_IN) {
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
try {
GoogleSignInAccount account = task.getResult(ApiException.class);
startAuth(account);
} catch (ApiException e) {
// TODO
Toast.makeText(getContext(), task.getException().getMessage(), Toast.LENGTH_LONG).show();
}
}
}
/**
* Starts authenticating user using GoogleSignInAccount
* @param account account to sign in with
*/
private void startAuth(GoogleSignInAccount account) {
AuthCredential credential = GoogleAuthProvider.getCredential(account.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(getActivity(), new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
FirebaseUser user = mAuth.getCurrentUser();
updateName(user);
userid = mAuth.getCurrentUser().getUid();
} else {
//TODO
}
}
});
}
/**
* Updates TextView to display current user's name
* @param user
*/
private void updateName(FirebaseUser user){
if(user!=null) {
String name = user.getDisplayName();
username.setText(name);
}
else{
username.setText("");
}
}
/**
* Checks if anyone is currently logged in and updates name
*/
private void checkLoginState(){
FirebaseUser user = mAuth.getCurrentUser();
updateName(user);
}
/**
* Starts an intent for google authentication
*/
private void signin(){
Intent intent = signInClient.getSignInIntent();
startActivityForResult(intent, RC_SIGN_IN);
}
/**
* Signs out current user and sets TextView of name empty
*/
private void signout(){
mAuth.signOut();
userid = null;
signInClient.signOut().addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
updateName(null);
}
});
}
/**
* Uploads all of current user's files to Firebase Storage
*/
private void syncFiles(){
if(userid!=null) {
File folder = getContext().getExternalFilesDir("media");
FirebaseStorage firebaseStorage = FirebaseStorage.getInstance();
StorageReference mStorageRef = firebaseStorage.getReference();
StorageMetadata metadata = new StorageMetadata.Builder().setContentType("video/mp4").build();
if (folder.exists()) {
File[] videos = folder.listFiles();
if (videos != null) {
for (File video : videos) {
Uri file = Uri.fromFile(video);
UploadTask uploadTask = mStorageRef.child(userid + "/" + file.getLastPathSegment()).putFile(file, metadata);
uploadTask.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Toast.makeText(getContext(), "Succefully synced", Toast.LENGTH_LONG).show();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
}
else{
Toast.makeText(getContext(), "Folder empty", Toast.LENGTH_LONG).show();
}
} else {
folder.mkdirs();
}
}
}
}
package com.isanga.securitycam;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
package com.isanga.securitycam.Models;
import java.io.File;
/**
* Clips model class for RecyclerView
*/
public class ClipsModel {
private String title;
private File thumbnail;
public ClipsModel(String title, File file) {
this.title = title;
this.thumbnail = file;
}
public String getTitle() {
return title;
}
public File getThumbnail() {
return thumbnail;
}
public void setTitle(String title) {
this.title = title;
}
public void setThumbnail(File thumbnail) {
this.thumbnail = thumbnail;
}
}
package com.isanga.securitycam.Models;
import androidx.core.content.FileProvider;
public class GenericFileProvider extends FileProvider {
}
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M9.4,10.5l4.77,-8.26C13.47,2.09 12.75,2 12,2c-2.4,0 -4.6,0.85 -6.32,2.25l3.66,6.35 0.06,-0.1zM21.54,9c-0.92,-2.92 -3.15,-5.26 -6,-6.34L11.88,9h9.66zM21.8,10h-7.49l0.29,0.5 4.76,8.25C21,16.97 22,14.61 22,12c0,-0.69 -0.07,-1.35 -0.2,-2zM8.54,12l-3.9,-6.75C3.01,7.03 2,9.39 2,12c0,0.69 0.07,1.35 0.2,2h7.49l-1.15,-2zM2.46,15c0.92,2.92 3.15,5.26 6,6.34L12.12,15L2.46,15zM13.73,15l-3.9,6.76c0.7,0.15 1.42,0.24 2.17,0.24 2.4,0 4.6,-0.85 6.32,-2.25l-3.66,-6.35 -0.93,1.6z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M13.05,9.79L10,7.5v9l3.05,-2.29L16,12zM13.05,9.79L10,7.5v9l3.05,-2.29L16,12zM13.05,9.79L10,7.5v9l3.05,-2.29L16,12zM11,4.07L11,2.05c-2.01,0.2 -3.84,1 -5.32,2.21L7.1,5.69c1.11,-0.86 2.44,-1.44 3.9,-1.62zM5.69,7.1L4.26,5.68C3.05,7.16 2.25,8.99 2.05,11h2.02c0.18,-1.46 0.76,-2.79 1.62,-3.9zM4.07,13L2.05,13c0.2,2.01 1,3.84 2.21,5.32l1.43,-1.43c-0.86,-1.1 -1.44,-2.43 -1.62,-3.89zM5.68,19.74C7.16,20.95 9,21.75 11,21.95v-2.02c-1.46,-0.18 -2.79,-0.76 -3.9,-1.62l-1.42,1.43zM22,12c0,5.16 -3.92,9.42 -8.95,9.95v-2.02C16.97,19.41 20,16.05 20,12s-3.03,-7.41 -6.95,-7.93L13.05,2.05C18.08,2.58 22,6.84 22,12z"/>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
tools:context=".Activities.MainActivity"
android:id="@+id/menu_drawer"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<TextView
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="@+id/toolbar"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fragment_container"/>
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:layout_height="match_parent"
android:id="@+id/navigation_view"
app:menu="@menu/gesture_menu_items"
android:layout_gravity= "start"/>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
</androidx.drawerlayout.widget.DrawerLayout>
\ No newline at end of file