Java tutorial
/* * Copyright 2017 Mahesh Gaya * * 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 edu.drake.research.android.lipswithmaps.activity; import android.Manifest; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.location.Location; import android.location.LocationManager; import android.net.wifi.ScanResult; import android.net.wifi.WifiManager; import android.support.annotation.NonNull; import android.support.design.widget.BottomSheetBehavior; import android.support.design.widget.CoordinatorLayout; import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.FrameLayout; import android.widget.TextView; import android.widget.Toast; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.SupportMapFragment; import com.google.android.gms.maps.model.CameraPosition; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.firebase.auth.AuthResult; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.auth.FirebaseUser; import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.ValueEventListener; import java.util.ArrayList; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import edu.drake.research.android.lipswithmaps.R; import edu.drake.research.android.lipswithmaps.adapter.WifiAdapter; import edu.drake.research.android.lipswithmaps.helper.Utils; import edu.drake.research.lipswithmaps.Accelerometer; import edu.drake.research.lipswithmaps.LocationLngLat; import edu.drake.research.lipswithmaps.Magnetometer; import edu.drake.research.lipswithmaps.Reading; import edu.drake.research.lipswithmaps.RotationMeter; import edu.drake.research.lipswithmaps.WifiItem; import static junit.framework.Assert.assertNotNull; public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback, SensorEventListener { //region TAG //Logging private final LatLng DRAKE_UNIVERSITY = new LatLng(41.6013800, -93.6518900); private static final String TAG = MapsActivity.class.getSimpleName(); //endregion //region constants private static final String locationPermission = Manifest.permission.ACCESS_FINE_LOCATION; //Permissions private static int LOCATION_REQUEST_CODE = 100; //endregion //region views //Binding views @BindView(R.id.toolbar) Toolbar mToolbar; @BindView(R.id.recycleview_wifi) RecyclerView mWifiRecycleView; @BindView(R.id.bottomsheet_wifilist) FrameLayout mWifiListBottomSheet; @BindView(R.id.textview_current_location) TextView mCurrentLocationTextView; @BindView(R.id.main_coordinator_layout) CoordinatorLayout mCoordinatorLayout; private BottomSheetBehavior mBottomSheetBehavior; //endregion //region sensors //Sensors - Accelerometer, magnetic private SensorManager mSensorManager; /* Measures the acceleration force in m/s2 that is applied to a device on all three physical axes (x, y, and z), including the force of gravity.*/ private Sensor mAccelerometer; /* Measures the ambient geomagnetic field for all three physical axes (x, y, z) in T. */ private Sensor mMagnetometer; /* Measures the orientation of a device by providing the three elements of the device's rotation vector. */ private Sensor mRotationMeter; /* Keeps values of the accelerometer */ private Accelerometer mAccelerometerValues; /* Keeps values of the magnetometer */ private Magnetometer mMagnetometerValues; /* Keeps values of the rotation */ private RotationMeter mRotationMeterValues; //endregion //region Map //Map variables private GoogleMap mMap; //endregion //region Wi-Fi //Wifi list private List<WifiItem> mWifiList; private WifiAdapter mWifiAdapter; //Wifi variables private List<ScanResult> mWifiScanResults; private WifiManager mWifiManager; final BroadcastReceiver mWifiScanReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { mWifiList.clear(); mWifiScanResults = mWifiManager.getScanResults(); for (ScanResult result : mWifiScanResults) { mWifiList.add(new WifiItem(result.SSID, result.BSSID, result.level)); } mWifiAdapter.notifyDataSetChanged(); } }; //endregion //region Firebase private FirebaseAuth mAuth; private FirebaseAuth.AuthStateListener mAuthListener; //endregion //region location manager //Location variables LocationManager mLocationManager; //get the location of the user with accuracy Location mLocation; //will contain the longitude and latitude obtained android.location.LocationListener mLocationListener = new android.location.LocationListener() { @Override public void onLocationChanged(Location location) { Toast.makeText(getApplicationContext(), "Location is updated", Toast.LENGTH_SHORT).show(); mLocation = location; mCurrentLocationTextView.setText("Time: " + Utils.getFriendlyDateTime(location.getTime()) + "\nLongitude: " + location.getLongitude() + "\t\tLatitude: " + location.getLatitude() + "\nAccuracy: " + location.getAccuracy() + "\t\tAltitude: " + location.getAltitude()); uploadContent(); } @Override public void onStatusChanged(String s, int i, Bundle bundle) { } @Override public void onProviderEnabled(String s) { } @Override public void onProviderDisabled(String s) { } }; //endregion //region Lifecycle methods @Override @SuppressWarnings({ "MissingPermission" }) protected void onStop() { try { unregisterReceiver(mWifiScanReceiver); } catch (java.lang.IllegalArgumentException e) { Log.e(TAG, "onStop: ", e); e.printStackTrace(); } if (mLocationManager != null) { //do not put permission here it will end up in an infinite loop mLocationManager.removeUpdates(mLocationListener); } if (mSensorManager != null) { mSensorManager.unregisterListener(this); } if (mAuthListener != null) { mAuth.removeAuthStateListener(mAuthListener); } super.onStop(); } /** * Sets up the toolbar */ private void setupToolbar() { //shows Action bar setSupportActionBar(mToolbar); } /** * Creates menu on the toolbar * @param menu * @return */ @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main_menu, menu); return true; } /** * Handles menu item click events * @param item * @return */ @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.pref_general. int id = item.getItemId(); switch (id) { case R.id.action_details: { mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); break; } case R.id.action_upload: { uploadContent(); break; } } return super.onOptionsItemSelected(item); } /** * Initializes the views and ask for permission * @param savedInstanceState */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_maps); ButterKnife.bind(this); //connect to firebase mAuth = FirebaseAuth.getInstance(); mAuthListener = new FirebaseAuth.AuthStateListener() { @Override public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { FirebaseUser user = firebaseAuth.getCurrentUser(); if (user != null) { // User is signed in Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid()); } else { // User is signed out Log.d(TAG, "onAuthStateChanged:signed_out"); } } }; mAuth.signInAnonymously().addOnCompleteListener(this, new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { Log.d(TAG, "signInAnonymously:onComplete:" + task.isSuccessful()); // If sign in fails, display a message to the user. If sign in succeeds // the auth state listener will be notified and logic to handle the // signed in user can be handled in the listener. if (!task.isSuccessful()) { Log.w(TAG, "signInAnonymously", task.getException()); Toast.makeText(getApplicationContext(), "Authentication failed.", Toast.LENGTH_SHORT).show(); } } }); setupToolbar(); initSensors(); //Initialize the containers and wifi adapters mWifiList = new ArrayList<>(); mWifiAdapter = new WifiAdapter(mWifiList); //Initialize the list view for the wifis RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext()); mWifiRecycleView.setLayoutManager(mLayoutManager); mWifiRecycleView.setItemAnimator(new DefaultItemAnimator()); mWifiRecycleView.setAdapter(mWifiAdapter); // Obtain the SupportMapFragment and get notified when the map is ready to be used. SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map); mapFragment.getMapAsync(this); //Initialize the wifi Broadcaster wifiScan(); askPermission(); mBottomSheetBehavior = BottomSheetBehavior.from(mWifiListBottomSheet); mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); } /** * Registers the listeners for the different sensors */ @Override protected void onStart() { super.onStart(); mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_FASTEST); mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_FASTEST); mSensorManager.registerListener(this, mRotationMeter, SensorManager.SENSOR_DELAY_FASTEST); mAuth.addAuthStateListener(mAuthListener); } //endregion //region Firebase /** * Create a new post object to be store to database * @return */ private Reading createPost() { Long currentTimeMillis = System.currentTimeMillis(); if (mLocation == null || mAccelerometerValues == null || mMagnetometerValues == null || mRotationMeterValues == null || mWifiList == null) { return null; } LocationLngLat location = new LocationLngLat(mLocation.getLatitude(), mLocation.getLongitude(), mLocation.getAccuracy()); return new Reading(currentTimeMillis, mWifiList, location, mAccelerometerValues, mMagnetometerValues, mRotationMeterValues, Utils.getPhoneInformation()); } /** * Uploads content to Firebase database */ private void uploadContent() { Reading reading = createPost(); if (reading == null) { Log.d(TAG, "onReceive: reading is null"); return; } DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference(Reading.TABLE_NAME); databaseReference = databaseReference.push(); databaseReference.setValue(reading); databaseReference.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { Log.d(TAG, "onDataChange: " + dataSnapshot.getKey()); } @Override public void onCancelled(DatabaseError databaseError) { Log.d(TAG, "onCancelled: " + databaseError.toString()); } }); } //endregion //region Location methods /** * Gets the current location */ private void getCurrentLongLat() { mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); //Check permission // Register the listener with the Location Manager to receive location updates if (ContextCompat.checkSelfPermission(this, locationPermission) == PackageManager.PERMISSION_GRANTED) { mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 0, mLocationListener); wifiScan(); } else { askPermission(); } } //endregion //region Permission methods /** * Based on Permission result, initialize the sensors or show rationale * @param requestCode * @param permissions * @param grantResults */ @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == LOCATION_REQUEST_CODE) { if (permissions.length == 1 && permissions[0].equals(locationPermission) && grantResults[0] == PackageManager.PERMISSION_GRANTED) { initializePermittedSensors(); } else { //Permission was denied. Display an error message. showRationale(); } } } /** * Shows rationale message * @return */ private boolean showRationale() { // Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale(this, locationPermission)) { // Show an explanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. Snackbar.make(mCoordinatorLayout, R.string.permission_location_rationale, Snackbar.LENGTH_INDEFINITE) .setAction(android.R.string.ok, new View.OnClickListener() { @Override public void onClick(View view) { ActivityCompat.requestPermissions(MapsActivity.this, new String[] { locationPermission }, LOCATION_REQUEST_CODE); } }).show(); } else { // No explanation needed, we can request the permission. try { ActivityCompat.requestPermissions(this, new String[] { locationPermission }, LOCATION_REQUEST_CODE); } catch (Exception e) { Log.e(TAG, "showRationale: ", e); } } return false; } /** * Ask for permission */ private void askPermission() { if (ContextCompat.checkSelfPermission(this, locationPermission) == PackageManager.PERMISSION_GRANTED) { initializePermittedSensors(); } else { showRationale(); } } //endregion //region WI-FI methods /** * get wifi scan */ private void wifiScan() { if (mWifiManager == null) { mWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); registerReceiver(mWifiScanReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); } mWifiManager.startScan(); } //endregion //region map methods /** * When map is ready, initialize the Map UI * @param googleMap */ @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; // mMap.addMarker(new MarkerOptions().position(DRAKE_UNIVERSITY).title("Drake University! Yay!")); // mMap.moveCamera(CameraUpdateFactory.newLatLng(drakeUniversity)); setCameraPosition(DRAKE_UNIVERSITY); enableCurrentLocationUI(); } /** * show current map UI */ private void enableCurrentLocationUI() { if (ContextCompat.checkSelfPermission(this, locationPermission) == PackageManager.PERMISSION_GRANTED) { if (mMap != null) { mMap.setMyLocationEnabled(true); } } } /** * Set the camera zoom * @param latitude * @param longitude */ public void setCameraPosition(double latitude, double longitude) { CameraPosition cameraPosition = new CameraPosition.Builder().target(new LatLng(latitude, longitude)) // Sets the center of the map .zoom(15) // Sets the zoom .build(); // Creates a CameraPosition from the builder mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); } /** * * @param position */ public void setCameraPosition(LatLng position) { CameraPosition cameraPosition = new CameraPosition.Builder().target(position) // Sets the center of the map .zoom(15) // Sets the zoom .build(); // Creates a CameraPosition from the builder mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); } //endregion //region Sensor methods /** * Initializes wifi and location sensors after permission is asked */ private void initializePermittedSensors() { getCurrentLongLat(); wifiScan(); } /** * initialize the meter sensors and other */ private void initSensors() { mSensorManager = (SensorManager) getApplicationContext().getSystemService(SENSOR_SERVICE); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); mRotationMeter = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); } /** * When sensors changes, update the values * @param event */ @Override public void onSensorChanged(SensorEvent event) { switch (event.sensor.getType()) { case Sensor.TYPE_ACCELEROMETER: { mAccelerometerValues = new Accelerometer(event.values[0], event.values[1], event.values[2]); break; } case Sensor.TYPE_MAGNETIC_FIELD: { mMagnetometerValues = new Magnetometer(event.values[0], event.values[1], event.values[2]); break; } case Sensor.TYPE_ROTATION_VECTOR: { mRotationMeterValues = new RotationMeter(event.values[0], event.values[1], event.values[2]); break; } } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } //endregion }