Java tutorial
/* * Copyright (C) 2016 Google, Inc. * * 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 com.pro.gen.android; import android.annotation.SuppressLint; import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; import android.support.design.widget.Snackbar; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import com.badlogic.gdx.Net; import com.badlogic.gdx.backends.android.AndroidFragmentApplication; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.Scopes; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks; import com.google.android.gms.common.api.Scope; import com.google.android.gms.fitness.Fitness; import com.google.android.gms.fitness.data.Bucket; import com.google.android.gms.fitness.data.DataPoint; import com.google.android.gms.fitness.data.DataSet; import com.google.android.gms.fitness.data.DataType; import com.google.android.gms.fitness.data.Field; import com.google.android.gms.fitness.request.DataReadRequest; import com.google.android.gms.fitness.result.DataReadResult; import com.pro.gen.App; import com.pro.gen.common.logger.Log; import com.pro.gen.common.logger.LogWrapper; import com.pro.gen.common.logger.MessageOnlyLogFilter; import com.pro.gen.managers.DatabaseManager; import com.pro.gen.managers.XmlManager; import com.pro.gen.utils.LogUtils; import com.pro.gen.utils.StepCallback; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import javax.net.ssl.HttpsURLConnection; import static java.text.DateFormat.getDateInstance; import static java.text.DateFormat.getTimeInstance; /** * This sample demonstrates how to use the History API of the Google Fit platform to insert data, * query against existing data, and remove data. It also demonstrates how to authenticate * a user with Google Play Services and how to properly represent data in a {@link DataSet}. */ public class MainActivity extends AppCompatActivity implements AndroidFragmentApplication.Callbacks, StepCallback { public static final String TAG = "BasicHistoryApi"; //private static final int REQUEST_OAUTH = 1; //private static final String DATE_FORMAT = "yyyy.MM.dd HH:mm:ss"; private boolean finished = false; /** * Track whether an authorization activity is stacking over the current activity, i.e. when * a known auth error is being resolved, such as showing the account chooser or presenting a * consent dialog. This avoids common duplications as might happen on screen rotations, etc. */ private static final String AUTH_PENDING = "auth_state_pending"; private static boolean authInProgress = false; private StringBuilder builder; private static final String MY_PREFS_NAME = "daysteps"; public static GoogleApiClient mClient = null; @Override protected void onCreate(Bundle savedInstanceState) { requestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.activity_main); GameFragment fragment = new GameFragment(); FragmentTransaction trans = getSupportFragmentManager().beginTransaction(); trans.replace(android.R.id.content, fragment); trans.commit(); // This method sets up our custom logger, which will print all log messages to the device // screen, as well as to adb logcat. initializeLogging(); if (savedInstanceState != null) { authInProgress = savedInstanceState.getBoolean(AUTH_PENDING); } buildFitnessClient(); } @Override public int getStepsSince(long time) { // Begin by creating the query. DataReadRequest readRequest = queryFitnessDataSince(time); // [START read_dataset] // Invoke the History API to fetch the data with the query and await the result of // the read request. DataReadResult dataReadResult = Fitness.HistoryApi.readData(mClient, readRequest).await(1, TimeUnit.MINUTES); // [END read_dataset] // For the sake of the sample, we'll print the data so we can see what we just added. // In general, logging fitness information should be avoided for privacy reasons. return getData(dataReadResult); } @SuppressLint("ValidFragment") protected class GameFragment extends AndroidFragmentApplication { // 5. Add the initializeForView() code in the Fragment's onCreateView method. @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { App app = new App(); app.setStepCallback(MainActivity.this); return initializeForView(new App()); } } /** * Build a {@link GoogleApiClient} that will authenticate the user and allow the application * to connect to Fitness APIs. The scopes included should match the scopes your app needs * (see documentation for details). Authentication will occasionally fail intentionally, * and in those cases, there will be a known resolution, which the OnConnectionFailedListener() * can address. Examples of this include the user never having signed in before, or * having multiple accounts on the device and needing to specify which account to use, etc. */ private void buildFitnessClient() { // Create the Google API Client mClient = new GoogleApiClient.Builder(this).addApi(Fitness.HISTORY_API) .addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE)) .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() { @Override public void onConnected(Bundle bundle) { Log.i(TAG, "Connected!!!"); // Now you can make calls to the Fitness APIs. What to do? // Look at some data!! SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE); String restoredText = prefs.getString("steps", null); DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd"); Calendar cal = Calendar.getInstance(); if (XmlManager.getInstance().getUsername().equals("")) { } else if (restoredText == null || !restoredText.equals(dateFormat.format(cal.getTime()))) { SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE) .edit(); editor.putString("steps", dateFormat.format(cal.getTime())); editor.commit(); builder = new StringBuilder(); new InsertAndVerifyDataTask().execute(); } //builder = new StringBuilder(); //new InsertAndVerifyDataTask().execute(); } @Override public void onConnectionSuspended(int i) { // If your connection to the sensor gets lost at some point, // you'll be able to determine the reason and react to it here. if (i == ConnectionCallbacks.CAUSE_NETWORK_LOST) { Log.i(TAG, "Connection lost. Cause: Network Lost."); } else if (i == ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) { Log.i(TAG, "Connection lost. Reason: Service Disconnected"); } } }).enableAutoManage(this, 0, new GoogleApiClient.OnConnectionFailedListener() { @Override public void onConnectionFailed(ConnectionResult result) { Log.i(TAG, "Google Play services connection failed. Cause: " + result.toString()); Snackbar.make(MainActivity.this.findViewById(R.id.main_activity_view), "Exception while connecting to Google Play services: " + result.getErrorMessage(), Snackbar.LENGTH_INDEFINITE).show(); } }).build(); } @Override public void exit() { } /** * Create a {@link DataSet} to insert data into the History API, and * then create and execute a {@link DataReadRequest} to verify the insertion succeeded. * By using an {@link AsyncTask}, we can schedule synchronous calls, so that we can query for * data after confirming that our insert was successful. Using asynchronous calls and callbacks * would not guarantee that the insertion had concluded before the read request was made. * An example of an asynchronous call using a callback can be found in the example * on deleting data below. */ private class InsertAndVerifyDataTask extends AsyncTask<Void, Void, Void> { protected Void doInBackground(Void... params) { // Begin by creating the query. DataReadRequest readRequest = queryFitnessData(); // [START read_dataset] // Invoke the History API to fetch the data with the query and await the result of // the read request. DataReadResult dataReadResult = Fitness.HistoryApi.readData(mClient, readRequest).await(1, TimeUnit.MINUTES); // [END read_dataset] // For the sake of the sample, we'll print the data so we can see what we just added. // In general, logging fitness information should be avoided for privacy reasons. printData(dataReadResult); //comments return null; } } /** * Return a {@link DataReadRequest} for all step count changes in the past week. */ public DataReadRequest queryFitnessData() { // [START build_read_data_request] // Setting a start and end date using a range of 1 week before this moment. Calendar cal = Calendar.getInstance(); Date now = new Date(); now.setHours(0); cal.setTime(now); long endTime = cal.getTimeInMillis(); cal.add(Calendar.DATE, -1); long startTime = cal.getTimeInMillis(); java.text.DateFormat dateFormat = getDateInstance(); Log.i(TAG, "Range Start: " + dateFormat.format(startTime)); Log.i(TAG, "Range End: " + dateFormat.format(endTime)); DataReadRequest readRequest = new DataReadRequest.Builder() // The data request can specify multiple data types to return, effectively // combining multiple data queries into one call. // In this example, it's very unlikely that the request is for several hundred // datapoints each consisting of a few steps and a timestamp. The more likely // scenario is wanting to see how many steps were walked per day, for 7 days. .aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA) // Analogous to a "Group By" in SQL, defines how data should be aggregated. // bucketByTime allows for a time span, whereas bucketBySession would allow // bucketing by "sessions", which would need to be defined in code. .bucketByTime(2, TimeUnit.MINUTES).setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS).build(); // [END build_read_data_request] return readRequest; } public DataReadRequest queryFitnessDataSince(long time) { // [START build_read_data_request] // Setting a start and end date using a range of 1 week before this moment. Calendar cal = Calendar.getInstance(); Date before = new Date(time); cal.setTime(before); long startTime = cal.getTimeInMillis(); long endTime = new Date().getTime(); java.text.DateFormat dateFormat = getDateInstance(); Log.i(TAG, "Range Start: " + dateFormat.format(startTime)); Log.i(TAG, "Range End: " + dateFormat.format(endTime)); DataReadRequest readRequest = new DataReadRequest.Builder() // The data request can specify multiple data types to return, effectively // combining multiple data queries into one call. // In this example, it's very unlikely that the request is for several hundred // datapoints each consisting of a few steps and a timestamp. The more likely // scenario is wanting to see how many steps were walked per day, for 7 days. .aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA) // Analogous to a "Group By" in SQL, defines how data should be aggregated. // bucketByTime allows for a time span, whereas bucketBySession would allow // bucketing by "sessions", which would need to be defined in code. .bucketByTime(1, TimeUnit.DAYS).setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS).build(); // [END build_read_data_request] return readRequest; } public int getData(DataReadResult dataReadResult) { // [START parse_read_data_result] // If the DataReadRequest object specified aggregated data, dataReadResult will be returned // as buckets containing DataSets, instead of just DataSets. int counter = 0; if (dataReadResult.getBuckets().size() > 0) { Log.i(TAG, "Number of returned buckets of DataSets is: " + dataReadResult.getBuckets().size()); for (Bucket bucket : dataReadResult.getBuckets()) { List<DataSet> dataSets = bucket.getDataSets(); for (DataSet dataSet : dataSets) { for (DataPoint dp : dataSet.getDataPoints()) { DateFormat dateFormat = getTimeInstance(); //Log.i(TAG, "Data point:"); //Log.i(TAG, "\tType: " + dp.getDataType().getName()); Log.i(TAG, "\tdate" + new SimpleDateFormat("yyyy-MM-dd H:m:s") .format(new Date(dp.getStartTime(TimeUnit.MILLISECONDS)))); Log.i(TAG, "\tStart: " + dateFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS))); Log.i(TAG, "\tEnd: " + dateFormat.format(dp.getEndTime(TimeUnit.MILLISECONDS))); for (Field field : dp.getDataType().getFields()) { Log.i(TAG, "\tField: " + field.getName() + " Value: " + dp.getValue(field)); counter += Integer.parseInt(dp.getValue(field).toString()); } } } } } return counter; // [END parse_read_data_result] } /** * Log a record of the query result. It's possible to get more constrained data sets by * specifying a data source or data type, but for demonstrative purposes here's how one would * dump all the data. In this sample, logging also prints to the device screen, so we can see * what the query returns, but your app should not log fitness information as a privacy * consideration. A better option would be to dump the data you receive to a local data * directory to avoid exposing it to other applications. */ public void printData(DataReadResult dataReadResult) { // [START parse_read_data_result] // If the DataReadRequest object specified aggregated data, dataReadResult will be returned // as buckets containing DataSets, instead of just DataSets. if (dataReadResult.getBuckets().size() > 0) { Log.i(TAG, "Number of returned buckets of DataSets is: " + dataReadResult.getBuckets().size()); for (Bucket bucket : dataReadResult.getBuckets()) { LogUtils.Log("Step 1"); List<DataSet> dataSets = bucket.getDataSets(); for (DataSet dataSet : dataSets) { LogUtils.Log("Step 2"); dumpDataSet(dataSet); } } try { HashMap<String, String> params = new HashMap<String, String>(); params.put("username", XmlManager.getInstance().getUsername()); String encodedString = URLEncoder.encode(builder.toString(), "UTF-8"); LogUtils.Log(builder.toString()); params.put("stepdata", encodedString); performPostCall("http://2firestudios.com/www/weeklysteps1.php", params); } catch (Exception e) { } Log.d("FINSIHED", "SENT"); // MainActivity.this.finish(); // startActivity(new Intent(MainActivity.this, AndroidLauncher.class)); } // [END parse_read_data_result] } // [START parse_dataset] private void dumpDataSet(DataSet dataSet) { DateFormat dateFormat = getTimeInstance(); LogUtils.Log("SIZE =" + dataSet.getDataPoints().size()); for (DataPoint dp : dataSet.getDataPoints()) { LogUtils.Log("Step 3"); //Log.i(TAG, "Data point:"); //Log.i(TAG, "\tType: " + dp.getDataType().getName()); builder.append("<DayEntry date=\"" + new SimpleDateFormat("yyyy-MM-dd H:m:s") .format(new Date(dp.getStartTime(TimeUnit.MILLISECONDS))) + "\" " + "starttime=\"" + dateFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)) + "\" " + "endtime=\"" + dateFormat.format(dp.getEndTime(TimeUnit.MILLISECONDS)) + "\" "); Log.d(TAG, "\tdate" + new SimpleDateFormat("yyyy-MM-dd H:m:s") .format(new Date(dp.getStartTime(TimeUnit.MILLISECONDS)))); Log.d(TAG, "\tStart: " + dateFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS))); Log.d(TAG, "\tEnd: " + dateFormat.format(dp.getEndTime(TimeUnit.MILLISECONDS))); for (Field field : dp.getDataType().getFields()) { Log.d(TAG, "\tField: " + field.getName() + " Value: " + dp.getValue(field)); builder.append("steps=\"" + dp.getValue(field) + "\""); } builder.append("></DayEntry>\n"); } } public String performPostCall(String requestURL, HashMap<String, String> postDataParams) { URL url; String response = ""; try { url = new URL(requestURL); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(15000); conn.setConnectTimeout(15000); conn.setRequestMethod("POST"); conn.setDoInput(true); conn.setDoOutput(true); OutputStream os = conn.getOutputStream(); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8")); writer.write(getPostDataString(postDataParams)); writer.flush(); writer.close(); os.close(); int responseCode = conn.getResponseCode(); Log.i(TAG, "" + responseCode); if (responseCode == HttpsURLConnection.HTTP_OK) { String line; BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); while ((line = br.readLine()) != null) { response += line; } } else { response = ""; } } catch (Exception e) { e.printStackTrace(); } return response; } private String getPostDataString(HashMap<String, String> params) throws UnsupportedEncodingException { StringBuilder result = new StringBuilder(); boolean first = true; for (Map.Entry<String, String> entry : params.entrySet()) { if (first) first = false; else result.append("&"); result.append(URLEncoder.encode(entry.getKey(), "UTF-8")); result.append("="); result.append(URLEncoder.encode(entry.getValue(), "UTF-8")); } return result.toString(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } /** * Initialize a custom log class that outputs both to in-app targets and logcat. */ private void initializeLogging() { // Wraps Android's native log framework. LogWrapper logWrapper = new LogWrapper(); // Using Log, front-end to the logging chain, emulates android.util.log method signatures. Log.setLogNode(logWrapper); // Filter strips out everything except the message text. MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter(); logWrapper.setNext(msgFilter); // On screen logging via a customized TextView. //LogView logView = (LogView) findViewById(R.id.sample_logview); // Fixing this lint error adds logic without benefit. //noinspection AndroidLintDeprecation //logView.setBackgroundColor(Color.WHITE); //msgFilter.setNext(logView); Log.i(TAG, "Ready."); } @Override protected void onResume() { Map<String, String> params = new HashMap<String, String>(); params.put("username", XmlManager.getInstance().getUsername()); DatabaseManager.getInstance().makeDBCall(DatabaseManager.OPENED, params, null); super.onResume(); } @Override protected void onPause() { Map<String, String> params = new HashMap<String, String>(); params.put("username", XmlManager.getInstance().getUsername()); DatabaseManager.getInstance().makeDBCall(DatabaseManager.CLOSED, params, new Net.HttpResponseListener() { @Override public void handleHttpResponse(Net.HttpResponse httpResponse) { LogUtils.Log("FINISHED CLOSING"); finished = true; } @Override public void failed(Throwable t) { } @Override public void cancelled() { } }); while (!finished) { } finished = false; super.onPause(); } }