package com.naman14.stools.fragments; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.location.Criteria; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.location.LocationProvider; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import com.naman14.stools.R; import com.naman14.stools.compass.CompassView; /** * Created by naman on 30/01/15. */ public class CompassFragment extends Fragment { public CompassFragment(){} private final float MAX_ROATE_DEGREE = 1.0f; private SensorManager mSensorManager; private Sensor mOrientationSensor; private LocationManager mLocationManager; private String mLocationProvider; private float mDirection; private float mTargetDirection; private AccelerateInterpolator mInterpolator; protected final Handler mHandler = new Handler(); private boolean mStopDrawing; View mCompassView; CompassView mPointer; TextView mLocationTextView; LinearLayout mDirectionLayout; LinearLayout mAngleLayout; protected Runnable mCompassViewUpdater = new Runnable() { @Override public void run() { if (mPointer != null && !mStopDrawing) { if (mDirection != mTargetDirection) { // calculate the short routine float to = mTargetDirection; if (to - mDirection > 180) { to -= 360; } else if (to - mDirection < -180) { to += 360; } // limit the max speed to MAX_ROTATE_DEGREE float distance = to - mDirection; if (Math.abs(distance) > MAX_ROATE_DEGREE) { distance = distance > 0 ? MAX_ROATE_DEGREE : (-1.0f * MAX_ROATE_DEGREE); } // need to slow down if the distance is short mDirection = normalizeDegree(mDirection + ((to - mDirection) * mInterpolator.getInterpolation(Math .abs(distance) > MAX_ROATE_DEGREE ? 0.4f : 0.3f))); mPointer.updateDirection(mDirection); } updateDirection(); mHandler.postDelayed(mCompassViewUpdater, 20); } } }; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_compass, container, false); mDirection = 0.0f; mTargetDirection = 0.0f; mInterpolator = new AccelerateInterpolator(); mStopDrawing = true; mPointer = (CompassView) rootView.findViewById(R.id.compass_pointer); mDirectionLayout = (LinearLayout) rootView.findViewById(R.id.layout_direction); mAngleLayout = (LinearLayout) rootView.findViewById(R.id.layout_angle); mPointer.setImageResource(R.drawable.compass); mCompassView = rootView.findViewById(R.id.view_compass); initServices(); return rootView; } @Override public void onResume() { super.onResume(); if (mOrientationSensor != null) { mSensorManager.registerListener(mOrientationSensorEventListener, mOrientationSensor, SensorManager.SENSOR_DELAY_GAME); } mStopDrawing = false; mHandler.postDelayed(mCompassViewUpdater, 20); } @Override public void onPause() { super.onPause(); mStopDrawing = true; if (mOrientationSensor != null) { mSensorManager.unregisterListener(mOrientationSensorEventListener); } if (mLocationProvider != null) { mLocationManager.removeUpdates(mLocationListener); } } private void initServices() { // sensor manager mSensorManager = (SensorManager) getActivity().getSystemService(Context.SENSOR_SERVICE); mOrientationSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION); // location manager mLocationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE); Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setAltitudeRequired(false); criteria.setBearingRequired(false); criteria.setCostAllowed(true); criteria.setPowerRequirement(Criteria.POWER_LOW); mLocationProvider = mLocationManager.getBestProvider(criteria, true); } private void updateDirection() { ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); mDirectionLayout.removeAllViews(); mAngleLayout.removeAllViews(); ImageView east = null; ImageView west = null; ImageView south = null; ImageView north = null; float direction = normalizeDegree(mTargetDirection * -1.0f); if (direction > 22.5f && direction < 157.5f) { // east east = new ImageView(getActivity()); east.setImageResource( R.drawable.e); east.setLayoutParams(lp); } else if (direction > 202.5f && direction < 337.5f) { // west west = new ImageView(getActivity()); west.setImageResource(R.drawable.w); west.setLayoutParams(lp); } if (direction > 112.5f && direction < 247.5f) { // south south = new ImageView(getActivity()); south.setImageResource( R.drawable.s); south.setLayoutParams(lp); } else if (direction < 67.5 || direction > 292.5f) { // north north = new ImageView(getActivity()); north.setImageResource(R.drawable.n); north.setLayoutParams(lp); } if (south != null) { mDirectionLayout.addView(south); } if (north != null) { mDirectionLayout.addView(north); } if (east != null) { mDirectionLayout.addView(east); } if (west != null) { mDirectionLayout.addView(west); } int direction2 = (int) direction; boolean show = false; if (direction2 >= 100) { mAngleLayout.addView(getNumberImage(direction2 / 100)); direction2 %= 100; show = true; } if (direction2 >= 10 || show) { mAngleLayout.addView(getNumberImage(direction2 / 10)); direction2 %= 10; } mAngleLayout.addView(getNumberImage(direction2)); ImageView degreeImageView = new ImageView(getActivity()); degreeImageView.setImageResource(R.drawable.degree); degreeImageView.setLayoutParams(lp); mAngleLayout.addView(degreeImageView); } private ImageView getNumberImage(int number) { ImageView image = new ImageView(getActivity()); ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); switch (number) { case 0: image.setImageResource(R.drawable.number_0); break; case 1: image.setImageResource(R.drawable.number_1); break; case 2: image.setImageResource(R.drawable.number_2); break; case 3: image.setImageResource(R.drawable.number_3); break; case 4: image.setImageResource(R.drawable.number_4); break; case 5: image.setImageResource(R.drawable.number_5); break; case 6: image.setImageResource(R.drawable.number_6); break; case 7: image.setImageResource(R.drawable.number_7); break; case 8: image.setImageResource(R.drawable.number_8); break; case 9: image.setImageResource(R.drawable.number_9); break; } image.setLayoutParams(lp); return image; } private void updateLocation(Location location) { if (location == null) { mLocationTextView.setText(R.string.getting_location); } else { StringBuilder sb = new StringBuilder(); double latitude = location.getLatitude(); double longitude = location.getLongitude(); if (latitude >= 0.0f) { sb.append(getString(R.string.location_north, getLocationString(latitude))); } else { sb.append(getString(R.string.location_south, getLocationString(-1.0 * latitude))); } sb.append(" "); if (longitude >= 0.0f) { sb.append(getString(R.string.location_east, getLocationString(longitude))); } else { sb.append(getString(R.string.location_west, getLocationString(-1.0 * longitude))); } mLocationTextView.setText(sb.toString()); } } private String getLocationString(double input) { int du = (int) input; int fen = (((int) ((input - du) * 3600))) / 60; int miao = (((int) ((input - du) * 3600))) % 60; return String.valueOf(du) + "°" + String.valueOf(fen) + "'" + String.valueOf(miao) + "\""; } private SensorEventListener mOrientationSensorEventListener = new SensorEventListener() { @Override public void onSensorChanged(SensorEvent event) { float direction = event.values[0] * -1.0f; mTargetDirection = normalizeDegree(direction); } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } }; private float normalizeDegree(float degree) { return (degree + 720) % 360; } LocationListener mLocationListener = new LocationListener() { @Override public void onStatusChanged(String provider, int status, Bundle extras) { if (status != LocationProvider.OUT_OF_SERVICE) { updateLocation(mLocationManager.getLastKnownLocation(mLocationProvider)); } else { mLocationTextView.setText(R.string.cannot_get_location); } } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } @Override public void onLocationChanged(Location location) { updateLocation(location); } }; }