From c2c75d0a0a4dd1f05a7206bbbfa913da14bfd066 Mon Sep 17 00:00:00 2001 From: nikhilchowdary Date: Mon, 20 Feb 2017 03:26:43 +0530 Subject: [PATCH] added google login and sync with google drive --- source-code/app/build.gradle | 8 +- source-code/app/google-services.json | 40 +++ source-code/app/src/main/AndroidManifest.xml | 6 + .../toolkit/activity/HomeActivity.java | 235 +++++++++++++++++- .../toolkit/fragment/DraftsFragment.java | 68 +++++ .../toolkit/fragment/LoadApkFragment.java | 66 +++++ .../toolkit/fragment/LoadProjectFragment.java | 74 ++++++ .../toolkit/fragment/SettingsFragment.java | 1 + .../toolkit/service/MyDriveEventService.java | 109 ++++++++ .../toolkit/service/UploadFileTask.java | 214 ++++++++++++++++ .../toolkit/utilities/CircleTransform.java | 48 ++++ .../main/res/drawable-hdpi/google_login.png | Bin 0 -> 2382 bytes .../app/src/main/res/drawable-hdpi/upload.png | Bin 0 -> 537 bytes .../main/res/drawable-mdpi/google_login.png | Bin 0 -> 1478 bytes .../app/src/main/res/drawable-mdpi/upload.png | Bin 0 -> 371 bytes .../main/res/drawable-xhdpi/google_login.png | Bin 0 -> 3338 bytes .../src/main/res/drawable-xhdpi/upload.png | Bin 0 -> 835 bytes .../main/res/drawable-xxhdpi/google_login.png | Bin 0 -> 5561 bytes .../src/main/res/drawable-xxhdpi/upload.png | Bin 0 -> 875 bytes .../listview_header_navigation_drawer.xml | 17 +- .../src/main/res/menu/menu_apk_selected.xml | 13 +- .../main/res/menu/menu_project_selected.xml | 15 +- .../app/src/main/res/menu/nav_drawer.xml | 5 + source-code/build.gradle | 2 +- source-code/gradle.properties | 1 + 25 files changed, 900 insertions(+), 22 deletions(-) create mode 100644 source-code/app/google-services.json create mode 100644 source-code/app/src/main/java/org/buildmlearn/toolkit/service/MyDriveEventService.java create mode 100644 source-code/app/src/main/java/org/buildmlearn/toolkit/service/UploadFileTask.java create mode 100644 source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/CircleTransform.java create mode 100644 source-code/app/src/main/res/drawable-hdpi/google_login.png create mode 100644 source-code/app/src/main/res/drawable-hdpi/upload.png create mode 100644 source-code/app/src/main/res/drawable-mdpi/google_login.png create mode 100644 source-code/app/src/main/res/drawable-mdpi/upload.png create mode 100644 source-code/app/src/main/res/drawable-xhdpi/google_login.png create mode 100644 source-code/app/src/main/res/drawable-xhdpi/upload.png create mode 100644 source-code/app/src/main/res/drawable-xxhdpi/google_login.png create mode 100644 source-code/app/src/main/res/drawable-xxhdpi/upload.png diff --git a/source-code/app/build.gradle b/source-code/app/build.gradle index 3ac948fd..62fd4cb2 100644 --- a/source-code/app/build.gradle +++ b/source-code/app/build.gradle @@ -68,10 +68,14 @@ dependencies { compile files('libs/prov-1.51.0.0.jar') compile files('libs/zipio-lib-1.8.jar') + compile 'com.google.android.gms:play-services-auth:9.8.0' + compile 'com.google.android.gms:play-services-drive:9.8.0' + compile 'com.squareup.picasso:picasso:2.5.2' compile 'org.jsoup:jsoup:1.9.1' - androidTestCompile 'com.android.support:support-annotations:23.4.0' + androidTestCompile 'com.android.support:support-annotations:24.0.0' androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2' androidTestCompile 'com.android.support.test:runner:0.5' androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.0.0' -} \ No newline at end of file +} +apply plugin: 'com.google.gms.google-services' \ No newline at end of file diff --git a/source-code/app/google-services.json b/source-code/app/google-services.json new file mode 100644 index 00000000..2f62af88 --- /dev/null +++ b/source-code/app/google-services.json @@ -0,0 +1,40 @@ +{ + "project_info": { + "project_number": "373868766583", + "project_id": "theta-bindery-158207" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:373868766583:android:dce0dccbf435c38d", + "android_client_info": { + "package_name": "org.buildmlearn.toolkit" + } + }, + "oauth_client": [ + { + "client_id": "373868766583-k2t8n2b4tajj0ota82ff7muu6ijlr0dp.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyD6aSOA0BXOe0mL2XQnPxfXd-7Uo5yZWs8" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 1 + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/source-code/app/src/main/AndroidManifest.xml b/source-code/app/src/main/AndroidManifest.xml index 518e1da0..f321f903 100755 --- a/source-code/app/src/main/AndroidManifest.xml +++ b/source-code/app/src/main/AndroidManifest.xml @@ -92,6 +92,12 @@ + + + + + + diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/HomeActivity.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/HomeActivity.java index 33153f57..b2ae197d 100755 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/HomeActivity.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/HomeActivity.java @@ -1,51 +1,93 @@ package org.buildmlearn.toolkit.activity; +import android.app.Activity; import android.app.Fragment; import android.app.FragmentTransaction; import android.content.Intent; import android.content.SharedPreferences; + import android.graphics.drawable.ColorDrawable; import android.os.Build; + + +import android.net.Uri; + import android.os.Bundle; import android.preference.PreferenceManager; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.design.widget.NavigationView; import android.app.FragmentManager; + import android.support.v4.content.ContextCompat; + + + import android.support.v4.view.GravityCompat; import android.os.Handler; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.AppCompatActivity; + import android.support.v7.widget.Toolbar; + + +import android.util.Log; +import android.view.Gravity; +import android.view.Menu; + import android.view.MenuItem; import android.view.View; +import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; +import com.google.android.gms.auth.api.Auth; +import com.google.android.gms.auth.api.signin.GoogleSignInOptions; +import com.google.android.gms.auth.api.signin.GoogleSignInResult; +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.GoogleApiAvailability; +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.common.api.ResultCallback; +import com.google.android.gms.common.api.Status; +import com.google.android.gms.drive.Drive; +import com.squareup.picasso.Picasso; + import org.buildmlearn.toolkit.R; import org.buildmlearn.toolkit.fragment.DraftsFragment; import org.buildmlearn.toolkit.fragment.HomeFragment; import org.buildmlearn.toolkit.fragment.LoadApkFragment; import org.buildmlearn.toolkit.fragment.LoadProjectFragment; import org.buildmlearn.toolkit.fragment.SettingsFragment; +import org.buildmlearn.toolkit.utilities.CircleTransform; import org.buildmlearn.toolkit.utilities.SmoothNavigationToggle; +import static org.buildmlearn.toolkit.R.drawable.logo_70; + /** * @brief Home screen of the application containg all the menus and settings. */ public class HomeActivity extends AppCompatActivity - implements NavigationView.OnNavigationItemSelectedListener { + implements NavigationView.OnNavigationItemSelectedListener , + GoogleApiClient.OnConnectionFailedListener,GoogleApiClient.ConnectionCallbacks{ private final String FRAGMENT_TAG_HOME = "Home"; private final String FRAGMENT_TAG_PROJECT = "Project"; private final String FRAGMENT_TAG_APK = "Apk"; private boolean backPressedOnce = false; + private static final int REQUEST_DRIVE_SIGNIN = 123; + private static final int REQUEST_GOOGLE_SIGN_IN =143; + public static GoogleApiClient mGoogleApiClient,mGoogleApiClient1; + + private Uri uri; + private SmoothNavigationToggle smoothNavigationToggle; private NavigationView navigationView; + /** * {@inheritDoc} */ @@ -66,7 +108,7 @@ protected void onCreate(Bundle savedInstanceState) { navigationView.setNavigationItemSelectedListener(this); View menuHeaderView = navigationView.getHeaderView(0); - final TextView name = (TextView) menuHeaderView.findViewById(R.id.name); + final TextView name = (TextView) menuHeaderView.findViewById(R.id.person_name); name.setText(String.format(" %s", prefs.getString(getString(R.string.key_user_name), ""))); @@ -76,7 +118,12 @@ protected void onCreate(Bundle savedInstanceState) { @Override public void onDrawerOpened(View drawerView) { super.onDrawerOpened(drawerView); - name.setText(String.format(" %s", prefs.getString(getString(R.string.key_user_name), ""))); + if((mGoogleApiClient !=null) &&(!(mGoogleApiClient.isConnected()))){ + + name.setText("Welcome "+String.format(" %s", prefs.getString(getString(R.string.key_user_name), ""))); + + } + LoadProjectFragment f = (LoadProjectFragment) getFragmentManager().findFragmentByTag(FRAGMENT_TAG_PROJECT); if (f != null) f.closeSearch(); @@ -96,6 +143,28 @@ public void onDrawerOpened(View drawerView) { if (getSupportActionBar() != null) { getSupportActionBar().setTitle(R.string.app_name); } + + mGoogleApiClient = new GoogleApiClient.Builder(this) + .addApi(Drive.API) + .addScope(Drive.SCOPE_FILE) + .addConnectionCallbacks(this) + .addScope(Drive.SCOPE_APPFOLDER) + .addOnConnectionFailedListener(this) + .build(); + + + GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestEmail() + .build(); + + + mGoogleApiClient1 = new GoogleApiClient.Builder(this) + .enableAutoManage(this , this ) + .addApi(Auth.GOOGLE_SIGN_IN_API, gso) + .build(); + + + } @SuppressWarnings("StatementWithEmptyBody") @@ -195,6 +264,25 @@ public void run() { } }); break; + case R.id.sign_in: + Menu menu = navigationView.getMenu(); + MenuItem aaa = menu.getItem(7); + if(mGoogleApiClient !=null){ + if("Sign Out".equals(aaa.getTitle())){ + aaa.setTitle("Sign In"); + mGoogleApiClient.clearDefaultAccountAndReconnect(); + mGoogleApiClient.disconnect(); + Auth.GoogleSignInApi.signOut(mGoogleApiClient1) + .setResultCallback(logout); + } + else { + mGoogleApiClient.connect(); + } + } + break; + default: + //do nothing + break; } DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); @@ -243,6 +331,147 @@ public void run() navigationView.setCheckedItem(R.id.nav_home); } } + + + @Override + public void onConnected(@Nullable Bundle bundle) { + + + + Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient1); + startActivityForResult(signInIntent, REQUEST_GOOGLE_SIGN_IN); + } + + @Override + public void onConnectionSuspended(int i) { + if(mGoogleApiClient!=null){ + mGoogleApiClient.disconnect(); + } + + } + + @Override + public void onConnectionFailed(@NonNull ConnectionResult result) { + if (!result.hasResolution()) { + GoogleApiAvailability.getInstance().getErrorDialog(this, result.getErrorCode(), 0).show(); + return; + } + try { + result.startResolutionForResult(this, REQUEST_DRIVE_SIGNIN); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + @Override + protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { + switch (requestCode) { + + case REQUEST_DRIVE_SIGNIN: + + if (resultCode == Activity.RESULT_OK) { + + mGoogleApiClient.connect(); + + } + else if (resultCode == RESULT_CANCELED){ + + Log.d("TAG","result cancelled"); + return ; + } + break; + + case REQUEST_GOOGLE_SIGN_IN: + + GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data); + + if (result.isSuccess()) { + + String name = result.getSignInAccount().getDisplayName(); + String email = result.getSignInAccount().getEmail(); + uri = result.getSignInAccount().getPhotoUrl(); + TextView personname = (TextView)findViewById(R.id.person_name); + Menu menu = navigationView.getMenu(); + MenuItem aaa = menu.getItem(7); + + aaa.setTitle("Sign Out"); + Picasso.with(this).load(uri).transform(new CircleTransform()).into((ImageView)findViewById(R.id.profile_pic)); + personname.setText("Welcome " + name); + Toast.makeText(this," connected "+email,Toast.LENGTH_SHORT).show(); + + + + } + else{ + + Toast.makeText(this,"No internet",Toast.LENGTH_SHORT).show(); + } + break; + default: + //do nothing + break; + + + } + } + + + @Override + protected void onPause() { + super.onPause(); + } + + + @Override + protected void onResume() { + + super.onResume(); + if (mGoogleApiClient == null) { + mGoogleApiClient = new GoogleApiClient.Builder(this) + .addApi(Drive.API) + .addScope(Drive.SCOPE_FILE) + .addConnectionCallbacks(this) + .addOnConnectionFailedListener(this) + .build(); + mGoogleApiClient.connect(); + } + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if ((mGoogleApiClient != null)&& (mGoogleApiClient.isConnected())){ + + mGoogleApiClient.clearDefaultAccountAndReconnect(); + mGoogleApiClient.disconnect(); + } + if ((mGoogleApiClient1 != null)&& (mGoogleApiClient1.isConnected())){ + + Auth.GoogleSignInApi.signOut(mGoogleApiClient1) + .setResultCallback(logout); + + + } + } + + /** + * logout is result callback defined to logout user from google sign in api + */ + + private ResultCallback logout= new ResultCallback() { + @Override + public void onResult(@NonNull Status status) { + + ImageView iv = (ImageView) findViewById(R.id.profile_pic); + Picasso.with(getApplicationContext()).load(logo_70).into(iv); + TextView personname = (TextView)findViewById(R.id.person_name); + personname.setText("Welcome"); + personname.setGravity(Gravity.CENTER); + + } + }; } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/DraftsFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/DraftsFragment.java index 9ab36303..5dd2ba7c 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/DraftsFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/DraftsFragment.java @@ -28,6 +28,7 @@ import org.buildmlearn.toolkit.constant.Constants; import org.buildmlearn.toolkit.model.SavedProject; import org.buildmlearn.toolkit.model.Template; +import org.buildmlearn.toolkit.service.UploadFileTask; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.xml.sax.SAXException; @@ -42,6 +43,8 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import static org.buildmlearn.toolkit.activity.HomeActivity.mGoogleApiClient; + /** * Created by scopeinfinity on 10/3/16. */ @@ -52,6 +55,7 @@ public class DraftsFragment extends Fragment implements AbsListView.OnItemClickListener { private static final String TAG = "Draft Project Fragment"; + private static final int SAVED_DRAFT_CATEGOTY = 3; private AbsListView mListView; private boolean showTemplateSelectedMenu; @@ -320,6 +324,42 @@ public void onClick(View v) { }); break; + case R.id.action_sync_saved_project: + if(mGoogleApiClient != null){ + if(mGoogleApiClient.isConnected()) { + + final AlertDialog dialog_sync = new AlertDialog.Builder(activity) + .setTitle("Sync to Drive") + .setMessage("Do you want to save the selected drafts to your drive") + .setPositiveButton(R.string.dialog_yes, null) + .setNegativeButton(R.string.dialog_no, null) + .create(); + + dialog_sync.show(); + + dialog_sync.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dialog_sync.dismiss(); + syncDrafts(); + restoreSelectedView(); + } + }); + } + else{ + + Toast.makeText(getActivity(),"Drive not connected",Toast.LENGTH_SHORT).show(); + mGoogleApiClient.connect(); + } + } + else{ + + Toast.makeText(getActivity(),"Drive not connected",Toast.LENGTH_SHORT).show(); + } + + + break; + case R.id.action_select_all: for(int i=0;i selectedPositions = mAdapter.getSelectedPositions(); + if (selectedPositions.size() == 1) { + Toast.makeText(activity, "Uploading Project", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(activity, "Uploading Projects", Toast.LENGTH_SHORT).show(); + } + + for (int selectedPosition : selectedPositions) { + + SavedProject project =draftProjects.get(selectedPosition); + File file = new File(project.getFile().getPath()); + + String [] strings =new String[4]; + + strings[0]=file.getName(); + strings[1]= String.valueOf(selectedPosition); + strings[2]=String.valueOf(SAVED_DRAFT_CATEGOTY); + strings[3]=file.getPath(); + + new UploadFileTask().execute(strings); + + } + } } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/LoadApkFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/LoadApkFragment.java index 45c86cae..08e8c8af 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/LoadApkFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/LoadApkFragment.java @@ -33,12 +33,15 @@ import org.buildmlearn.toolkit.ToolkitApplication; import org.buildmlearn.toolkit.adapter.SavedApiAdapter; import org.buildmlearn.toolkit.model.SavedApi; +import org.buildmlearn.toolkit.service.UploadFileTask; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import static org.buildmlearn.toolkit.activity.HomeActivity.mGoogleApiClient; + /** * Created by opticod (Anupam Das) on 29/2/16. * @@ -48,6 +51,7 @@ public class LoadApkFragment extends Fragment implements AbsListView.OnItemClickListener { private static final String TAG = "Load API Fragment"; + private static final int APK_CATEGOTY = 1; private AbsListView mListView; private boolean showTemplateSelectedMenu; @@ -340,6 +344,40 @@ public void onClick(View v) { } }); break; + + case R.id.action_sync: + + + if(mGoogleApiClient != null){ + if(mGoogleApiClient.isConnected()) { + final AlertDialog dialog_sync = new AlertDialog.Builder(activity) + .setTitle("Sync to Drive") + .setMessage("Do you want to save the selected Apks to your drive") + .setPositiveButton(R.string.dialog_yes, null) + .setNegativeButton(R.string.dialog_no, null) + .create(); + dialog_sync.show(); + dialog_sync.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dialog_sync.dismiss(); + syncApks(); + restoreSelectedView(); + } + }); + } + else{ + Toast.makeText(getActivity(),"google drive is not connected",Toast.LENGTH_SHORT).show(); + mGoogleApiClient.connect(); + } + } + else{ + Toast.makeText(getActivity(),"Please sign in to upload",Toast.LENGTH_SHORT).show(); + } + + + break; + case R.id.action_share: ArrayList selectedPositions = mAdapter.getSelectedPositions(); @@ -503,5 +541,33 @@ public void closeSearch() { } + /** + * @brief Calls the async task to sync the apk to drive sequentially + */ + public void syncApks() { + ArrayList selectedPositions = mAdapter.getSelectedPositions(); + if (selectedPositions.size() == 1) { + Toast.makeText(activity, "Uploading Apk", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(activity, "Uploading Apk's", Toast.LENGTH_SHORT).show(); + } + + for (int selectedPosition : selectedPositions) { + SavedApi apk = savedApis.get(selectedPosition); + File file = new File(apk.getFile().getPath()); + + String [] strings =new String[4]; + + strings[0]=file.getName(); + strings[1]= String.valueOf(selectedPosition); + strings[2]=String.valueOf(APK_CATEGOTY); + strings[3]=file.getPath(); + + new UploadFileTask().execute(strings); + + } + } + + } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/LoadProjectFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/LoadProjectFragment.java index ab3f7d52..a4df7647 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/LoadProjectFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/LoadProjectFragment.java @@ -37,6 +37,7 @@ import org.buildmlearn.toolkit.constant.Constants; import org.buildmlearn.toolkit.model.SavedProject; import org.buildmlearn.toolkit.model.Template; +import org.buildmlearn.toolkit.service.UploadFileTask; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.xml.sax.SAXException; @@ -51,12 +52,15 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import static org.buildmlearn.toolkit.activity.HomeActivity.mGoogleApiClient; + /** * @brief Fragment used for loading existing projects into a list. */ public class LoadProjectFragment extends Fragment implements AbsListView.OnItemClickListener { private static final String TAG = "Load Project Fragment"; + private static final int SAVED_PROJECT_CATEGOTY = 2; private AbsListView mListView; private boolean showTemplateSelectedMenu; @@ -68,6 +72,7 @@ public class LoadProjectFragment extends Fragment implements AbsListView.OnItemC private boolean isSearchOpened = false; private EditText editSearch; + public static int semaphore = 1; /** * {@inheritDoc} @@ -378,6 +383,45 @@ public void onClick(View v) { } }); break; + + case R.id.action_sync_saved_project: + + + if(mGoogleApiClient != null){ + if(mGoogleApiClient.isConnected()) { + + final AlertDialog dialog_sync = new AlertDialog.Builder(activity) + .setTitle("Sync to Drive") + .setMessage("Do you want to save the selected projects to your drive") + .setPositiveButton(R.string.dialog_yes, null) + .setNegativeButton(R.string.dialog_no, null) + .create(); + + dialog_sync.show(); + + dialog_sync.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dialog_sync.dismiss(); + syncProjects(); + restoreSelectedView(); + } + }); + } + else{ + + Toast.makeText(getActivity(),"Drive not connected",Toast.LENGTH_SHORT).show(); + mGoogleApiClient.connect(); + } + } + else{ + + Toast.makeText(getActivity(),"Drive not connected",Toast.LENGTH_SHORT).show(); + } + + + break; + case R.id.action_share: ArrayList selectedPositions = mAdapter.getSelectedPositions(); @@ -394,6 +438,7 @@ public void onClick(View v) { sendIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); startActivity(Intent.createChooser(sendIntent, null)); break; + case R.id.action_search: isSearchOpened = true; @@ -544,4 +589,33 @@ public void closeSearch() { } } + + + /** + * Calls the asyc task to sync the project to drive sequentially + */ + public void syncProjects() { + ArrayList selectedPositions = mAdapter.getSelectedPositions(); + if (selectedPositions.size() == 1) { + Toast.makeText(activity, "Uploading Project", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(activity, "Uploading Projects", Toast.LENGTH_SHORT).show(); + } + + for (int selectedPosition : selectedPositions) { + + SavedProject project =savedProjects.get(selectedPosition); + File file = new File(project.getFile().getPath()); + + String [] strings =new String[4]; + + strings[0]=file.getName(); + strings[1]= String.valueOf(selectedPosition); + strings[2]=String.valueOf(SAVED_PROJECT_CATEGOTY); + strings[3]=file.getPath(); + + new UploadFileTask().execute(strings); + + } + } } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/SettingsFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/SettingsFragment.java index 4dca9b73..47ce35d4 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/SettingsFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/SettingsFragment.java @@ -33,6 +33,7 @@ /** * Created by abhishek on 21/06/15 at 9:51 PM. */ + public class SettingsFragment extends PreferenceFragment { private static final int REQUEST_PICK_APK = 9985; diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/service/MyDriveEventService.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/service/MyDriveEventService.java new file mode 100644 index 00000000..739de5f5 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/service/MyDriveEventService.java @@ -0,0 +1,109 @@ +package org.buildmlearn.toolkit.service; + +/** + * Created by iit2014094 on 2/19/2017. + */ + +import android.app.NotificationManager; +import android.content.Context; +import android.media.RingtoneManager; +import android.net.Uri; +import android.support.v4.app.NotificationCompat; +import android.util.Log; + +import com.google.android.gms.drive.Drive; +import com.google.android.gms.drive.DriveFile; +import com.google.android.gms.drive.DriveId; +import com.google.android.gms.drive.DriveResource; +import com.google.android.gms.drive.Metadata; +import com.google.android.gms.drive.events.CompletionEvent; +import com.google.android.gms.drive.events.DriveEventService; + +import org.buildmlearn.toolkit.R; + + +import static org.buildmlearn.toolkit.activity.HomeActivity.mGoogleApiClient; +import static org.buildmlearn.toolkit.fragment.LoadProjectFragment.semaphore; + +/** + * Created by iit2014094 on 2/15/2017. + */ + +public class MyDriveEventService extends DriveEventService { + + /** + * oncompletion method is called upon completion of sync of each apk/project or on failure of sync + */ + @Override + public void onCompletion(CompletionEvent event) { + Log.d("TAG", "Action completed with status: " + event.getStatus()); + + if (event.getStatus() == CompletionEvent.STATUS_SUCCESS) { + + DriveId driveId = event.getDriveId(); + DriveFile file = Drive.DriveApi.getFile(mGoogleApiClient, driveId); + DriveResource.MetadataResult result = file.getMetadata(mGoogleApiClient).await(); + if (!result.getStatus().isSuccess()) { + + semaphore++; + event.dismiss(); + return; + } + Metadata metadata = result.getMetadata(); + + Log.d("TAGGG","Metadata succesfully fetched. Title: " + metadata.getTitle()); + + Uri uri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + + NotificationCompat.Builder mBuilder = + new NotificationCompat.Builder(this) + .setSmallIcon(R.drawable.activated_background) + .setSound(uri) + .setContentTitle(metadata.getTitle()) + .setContentText("Successfully synced with drive"); + + NotificationManager mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + + mNotificationManager.notify((int) (Math.random()*255), mBuilder.build()); + semaphore++; + + } + + if (event.getStatus() == CompletionEvent.STATUS_FAILURE) { + + + + DriveId driveId = event.getDriveId(); + DriveFile file = Drive.DriveApi.getFile(mGoogleApiClient, driveId); + DriveResource.MetadataResult result = file.getMetadata(mGoogleApiClient).await(); + if (!result.getStatus().isSuccess()) { + event.dismiss(); + return; + } + Metadata metadata = result.getMetadata(); + + Log.d("TAGGG","Metadata succesfully fetched. Title: " + metadata.getTitle()); + + Uri uri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + + NotificationCompat.Builder mBuilder = + new NotificationCompat.Builder(this) + .setSmallIcon(R.drawable.activated_background) + .setSound(uri) + .setContentTitle(metadata.getTitle()) + .setContentText("failed to sync with drive"); + + NotificationManager mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + + mNotificationManager.notify((int) (Math.random()*255), mBuilder.build()); + + semaphore ++; + return ; + + } + + event.dismiss(); + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/service/UploadFileTask.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/service/UploadFileTask.java new file mode 100644 index 00000000..fc5190a7 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/service/UploadFileTask.java @@ -0,0 +1,214 @@ +package org.buildmlearn.toolkit.service; + +import android.os.AsyncTask; +import android.support.annotation.NonNull; +import android.util.Log; + +import com.google.android.gms.common.api.ResultCallback; +import com.google.android.gms.drive.Drive; +import com.google.android.gms.drive.DriveApi; + +import com.google.android.gms.drive.DriveFile; +import com.google.android.gms.drive.DriveFolder; +import com.google.android.gms.drive.DriveId; +import com.google.android.gms.drive.ExecutionOptions; +import com.google.android.gms.drive.MetadataChangeSet; +import com.google.android.gms.drive.query.Filters; +import com.google.android.gms.drive.query.Query; +import com.google.android.gms.drive.query.SearchableField; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import static org.buildmlearn.toolkit.activity.HomeActivity.mGoogleApiClient; + +/** + * Created by iit2014094 on 2/20/2017. + */ + +public class UploadFileTask extends AsyncTask{ + + private DriveFile driveFile; + private String path,nameOfFile; + + + @Override + protected Void doInBackground(String... strings) { + + nameOfFile = strings[0]; + path =strings[3]; + + + Query query = new Query.Builder() + .addFilter(Filters.eq(SearchableField.TITLE,strings[0])) + .build(); + + Drive.DriveApi.query(mGoogleApiClient, query) + .setResultCallback(metadataCallback); + + return null; + } + + /** + * Handles whether to create a new apk/saved project/draft in the google drive or update the already persent apk/saved project/draft + */ + private ResultCallback metadataCallback = + new ResultCallback() { + @Override + public void onResult(@NonNull DriveApi.MetadataBufferResult metadataBufferResult) { + if (!metadataBufferResult.getStatus().isSuccess()) { + Log.d("TAG","No internet connection"); + return ; + } + + int results = metadataBufferResult.getMetadataBuffer().getCount(); + + //if apk /saved project/draft is already present in drive + if (results > 0) { + + DriveId driveId = metadataBufferResult.getMetadataBuffer().get(0).getDriveId(); + driveFile = driveId.asDriveFile(); + + //open the drivefile and call to result callback to update it + driveFile.open(mGoogleApiClient, DriveFile.MODE_WRITE_ONLY, null) + .setResultCallback(driveContentsCallback); + + } + //if apk / saved file/draft is not present in the drive + else if(results == 0){ + + //call to result callback to create new apk /new saved project/new draft in the drive + Drive.DriveApi.newDriveContents(mGoogleApiClient) + .setResultCallback(newContentsCallback); + } + } + }; + + /** + * updates the already exisiting apk/saved project/draft in the drive + */ + + private ResultCallback driveContentsCallback = + new ResultCallback() { + @Override + public void onResult(@NonNull DriveApi.DriveContentsResult driveContentsResult) { + if (!driveContentsResult.getStatus().isSuccess()) { + driveFile.open(mGoogleApiClient, DriveFile.MODE_WRITE_ONLY, null) + .setResultCallback(driveContentsCallback); + return; + } + + OutputStream outputStream = driveContentsResult.getDriveContents().getOutputStream(); + + try { + + File tempFile = new File(path); + byte[] bytefile =readFile(tempFile); + outputStream.write(bytefile); + + } catch (IOException e) { + e.printStackTrace(); + } + + //get notification after completion of sync of apk/saved project/draft + ExecutionOptions executionOptions = new ExecutionOptions.Builder() + .setNotifyOnCompletion(true) + .build(); + + //sync the apk/saved project/draft with the drive + driveContentsResult.getDriveContents().commit(mGoogleApiClient, null, executionOptions) + .setResultCallback(new ResultCallback() { + @Override + public void onResult(@NonNull com.google.android.gms.common.api.Status status) { + Log.d("TAG","onresult callback recieved"); + + } + }); + + } + + /** + * converts the given file data into byte array and returns it + */ + + private byte[] readFile(File file) throws IOException { + + ByteArrayOutputStream ous = null; + InputStream ios = null; + try { + byte[] buffer = new byte[400096]; + ous = new ByteArrayOutputStream(); + ios = new FileInputStream(file); + int read; + while ((read = ios.read(buffer)) != -1) { + ous.write(buffer, 0, read); + } + } finally { + try { + if (ous != null) + ous.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + try { + if (ios != null) + ios.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return ous.toByteArray(); + } + }; + + /** + * creates new apk/draft/saved project in the drive and initializes its contents to null + * + */ + + private ResultCallback newContentsCallback = + new ResultCallback() { + @Override + public void onResult(@NonNull DriveApi.DriveContentsResult driveContentsResult) { + + if (!driveContentsResult.getStatus().isSuccess()) { + return; + } + + Log.d("TAG","sucessful recieving of drive contents"); + + + //providing metadata for the new apk /saved project/draft + MetadataChangeSet changeSet = new MetadataChangeSet.Builder() + .setTitle(nameOfFile) + .setMimeType("*/*") + .build(); + + + //create the new apk /saved project/draft without data + Drive.DriveApi.getRootFolder(mGoogleApiClient) + .createFile(mGoogleApiClient, changeSet, null) + .setResultCallback(new ResultCallback() { + @Override + public void onResult(@NonNull DriveFolder.DriveFileResult driveFileResult) { + Log.d("TAG","New File Succesfully created"); + } + }); + + + //build the query for the apk /saved project/draft + Query query = new Query.Builder() + .addFilter(Filters.eq(SearchableField.TITLE,nameOfFile)) + + .build(); + + //query the drive again for the apk/draft/saved project + Drive.DriveApi.query(mGoogleApiClient, query).setResultCallback(metadataCallback); + } + }; +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/CircleTransform.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/CircleTransform.java new file mode 100644 index 00000000..7b001d56 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/CircleTransform.java @@ -0,0 +1,48 @@ +package org.buildmlearn.toolkit.utilities; + +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Paint; + +import com.squareup.picasso.Transformation; + + +/** + * Created by iit2014094 on 2/10/2017. + */ +public class CircleTransform implements Transformation { + + @Override + public Bitmap transform(Bitmap source) { + int size = Math.min(source.getWidth(), source.getHeight()); + + int x = (source.getWidth() - size) / 2; + int y = (source.getHeight() - size) / 2; + + Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size); + if (!(squaredBitmap.equals(source))) { + source.recycle(); + } + + Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig()); + + Canvas canvas = new Canvas(bitmap); + Paint paint = new Paint(); + BitmapShader shader = new BitmapShader(squaredBitmap, + BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP); + paint.setShader(shader); + paint.setAntiAlias(true); + + float r = size / 2f; + canvas.drawCircle(r, r, r, paint); + + squaredBitmap.recycle(); + return bitmap; + } + + @Override + public String key() { + return "circle"; + } +} diff --git a/source-code/app/src/main/res/drawable-hdpi/google_login.png b/source-code/app/src/main/res/drawable-hdpi/google_login.png new file mode 100644 index 0000000000000000000000000000000000000000..a717d61a4301fee11c35fed31ff39c02d8728cb5 GIT binary patch literal 2382 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 literal 0 HcmV?d00001 diff --git a/source-code/app/src/main/res/drawable-mdpi/upload.png b/source-code/app/src/main/res/drawable-mdpi/upload.png new file mode 100644 index 0000000000000000000000000000000000000000..5f1929e117d2a3d7670179cd9c7e567d1a675046 GIT binary patch literal 371 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 literal 0 HcmV?d00001 diff --git a/source-code/app/src/main/res/drawable-xxhdpi/google_login.png b/source-code/app/src/main/res/drawable-xxhdpi/google_login.png new file mode 100644 index 0000000000000000000000000000000000000000..273d232f1dc077744c6254fccaa12a1ed02ab33c GIT binary patch literal 5561 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 Hu0mjf+)a_( literal 0 HcmV?d00001 diff --git a/source-code/app/src/main/res/drawable-xxhdpi/upload.png b/source-code/app/src/main/res/drawable-xxhdpi/upload.png new file mode 100644 index 0000000000000000000000000000000000000000..1043e1d73f5e237c87aa878d6472fb3fcab854ed GIT binary patch literal 875 zcmeAS@N?(olHy`uVBq!ia0vp^DImJ;QtW${pU(-8TtFxTMFf*ouxdjy$|>Yh;G`L3bo=+NWr^|J0++QoFQmsJnl zCY|>G^3EZE$N2WsIiG#L?4A;|^PvU%vu|F7tee;ti`cR!rM(?&5Bu2X3WYb8t-1Ov<%Up5AEKay?byTrYi z^@uT-=n{1|?T&B}DUbXfIR&}E84B{;->36EEjw}O@ACTpd%k$e+KPSX{CD|G-i60o z&lozc3-Wqztg+g#Dpqm-$8!s&NKf6K_U*2aRIM)W6Nv(@rCf{6Pn_x3*K)ID*E+%C zWqOQbg0P6yF*Swy0J*boB==5P{;cXRpQUZtxt(*abH6@*<^JC<+Dljylz3 zzH_kf9F-F0SZ%VyT_Hi^+6;$?r3Y=97@apBV>zV7`%aKUqRUi`mPT&8ps>c{j4e~* zHMTNNmX0Gbf*hO8Hh3#Is66X%n6b4n_OL_Ix%>nFPAL1Qh0QCt@- + android:id="@+id/nav_text" + android:layout_alignParentRight="true" + android:layout_alignParentEnd="true"> + android:textSize="@dimen/sub_title" + android:gravity="center"/> - \ No newline at end of file diff --git a/source-code/app/src/main/res/menu/menu_apk_selected.xml b/source-code/app/src/main/res/menu/menu_apk_selected.xml index 0e42d42a..50d2eecb 100644 --- a/source-code/app/src/main/res/menu/menu_apk_selected.xml +++ b/source-code/app/src/main/res/menu/menu_apk_selected.xml @@ -3,10 +3,17 @@ xmlns:tools="http://schemas.android.com/tools" tools:context="org.buildmlearn.toolkit.fragment.LoadProjectFragment"> + + @@ -20,7 +27,7 @@ @@ -28,7 +35,7 @@ diff --git a/source-code/app/src/main/res/menu/menu_project_selected.xml b/source-code/app/src/main/res/menu/menu_project_selected.xml index 0e42d42a..2f0e1f41 100644 --- a/source-code/app/src/main/res/menu/menu_project_selected.xml +++ b/source-code/app/src/main/res/menu/menu_project_selected.xml @@ -3,24 +3,31 @@ xmlns:tools="http://schemas.android.com/tools" tools:context="org.buildmlearn.toolkit.fragment.LoadProjectFragment"> + + @@ -28,7 +35,7 @@ diff --git a/source-code/app/src/main/res/menu/nav_drawer.xml b/source-code/app/src/main/res/menu/nav_drawer.xml index 0b33648b..4595d1f3 100644 --- a/source-code/app/src/main/res/menu/nav_drawer.xml +++ b/source-code/app/src/main/res/menu/nav_drawer.xml @@ -48,6 +48,11 @@ android:icon="@drawable/menu_info" android:title="@string/menu_about_us" android:visible="true" /> + diff --git a/source-code/build.gradle b/source-code/build.gradle index 18cedec8..592d656a 100644 --- a/source-code/build.gradle +++ b/source-code/build.gradle @@ -7,7 +7,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:2.2.3' - + classpath 'com.google.gms:google-services:3.0.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } diff --git a/source-code/gradle.properties b/source-code/gradle.properties index 74d56b1f..1c860c5a 100644 --- a/source-code/gradle.properties +++ b/source-code/gradle.properties @@ -13,3 +13,4 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true #Sat Jan 14 09:01:08 IST 2017 +