Java tutorial
/* * Copyright (C) 2008-2013 The Android Open Source Project, * Sean J. Barbeau * * 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.android.gpstest; import com.android.gpstest.util.GpsTestUtil; import com.android.gpstest.util.MathUtils; import com.android.gpstest.view.ViewPagerMapBevelScroll; import com.github.espiandev.showcaseview.ShowcaseView; import android.annotation.TargetApi; import android.app.ActionBar; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.hardware.GeomagneticField; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.location.GpsStatus; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.location.LocationProvider; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.provider.Settings; import android.support.v4.app.ActivityCompat; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.app.FragmentTransaction; import android.support.v4.view.MenuItemCompat; import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBarActivity; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.Surface; import android.view.View; import android.view.Window; import android.widget.CompoundButton; import android.widget.Toast; import java.util.ArrayList; public class GpsTestActivity extends ActionBarActivity implements LocationListener, GpsStatus.Listener, android.support.v7.app.ActionBar.TabListener, SensorEventListener { private static final String TAG = "GpsTestActivity"; private static final int SECONDS_TO_MILLISECONDS = 1000; static boolean mIsLargeScreen = false; private static GpsTestActivity sInstance; // Holds sensor data private static float[] mRotationMatrix = new float[16]; private static float[] mRemappedMatrix = new float[16]; private static float[] mValues = new float[3]; private static float[] mTruncatedRotationVector = new float[4]; private static boolean mTruncateVector = false; boolean mStarted; boolean mFaceTrueNorth; String mTtff; org.jraf.android.backport.switchwidget.Switch mSwitch; //GPS on/off switch SectionsPagerAdapter mSectionsPagerAdapter; ViewPagerMapBevelScroll mViewPager; ShowcaseView sv; ShowcaseView.ConfigOptions mOptions = new ShowcaseView.ConfigOptions(); private LocationManager mService; private LocationProvider mProvider; private GpsStatus mStatus; private ArrayList<GpsTestListener> mGpsTestListeners = new ArrayList<GpsTestListener>(); private Location mLastLocation; private GeomagneticField mGeomagneticField; private long minTime; // Min Time between location updates, in milliseconds private float minDistance; // Min Distance between location updates, in meters private SensorManager mSensorManager; static GpsTestActivity getInstance() { return sInstance; } void addListener(GpsTestListener listener) { mGpsTestListeners.add(listener); } private synchronized void gpsStart() { if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } if (!mStarted) { mService.requestLocationUpdates(mProvider.getName(), minTime, minDistance, this); mStarted = true; // Show Toast only if the user has set minTime or minDistance to something other than default values if (minTime != (long) (Double.valueOf(getString(R.string.pref_gps_min_time_default_sec)) * SECONDS_TO_MILLISECONDS) || minDistance != Float.valueOf(getString(R.string.pref_gps_min_distance_default_meters))) { Toast.makeText(this, String.format(getString(R.string.gps_set_location_listener), String.valueOf((double) minTime / SECONDS_TO_MILLISECONDS), String.valueOf(minDistance)), Toast.LENGTH_SHORT).show(); } // Show the indeterminate progress bar on the action bar until first GPS status is shown setSupportProgressBarIndeterminateVisibility(Boolean.TRUE); // Reset the options menu to trigger updates to action bar menu items invalidateOptionsMenu(); } for (GpsTestListener listener : mGpsTestListeners) { listener.gpsStart(); } } private synchronized void gpsStop() { if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } if (mStarted) { mService.removeUpdates(this); mStarted = false; // Stop progress bar setSupportProgressBarIndeterminateVisibility(Boolean.FALSE); // Reset the options menu to trigger updates to action bar menu items invalidateOptionsMenu(); } for (GpsTestListener listener : mGpsTestListeners) { listener.gpsStop(); } } private boolean sendExtraCommand(String command) { return mService.sendExtraCommand(LocationManager.GPS_PROVIDER, command, null); } /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); super.onCreate(savedInstanceState); sInstance = this; // Set the default values from the XML file if this is the first // execution of the app PreferenceManager.setDefaultValues(this, R.xml.preferences, false); mService = (LocationManager) getSystemService(Context.LOCATION_SERVICE); if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // Permission Denied Toast.makeText(this, getString(R.string.permission_denied), Toast.LENGTH_SHORT).show(); finish(); return; } else { mProvider = mService.getProvider(LocationManager.GPS_PROVIDER); if (mProvider == null) { Log.e(TAG, "Unable to get GPS_PROVIDER"); Toast.makeText(this, getString(R.string.gps_not_supported), Toast.LENGTH_SHORT).show(); finish(); return; } } mService.addGpsStatusListener(this); mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); // If we have a large screen, show all the fragments in one layout if (GpsTestUtil.isLargeScreen(this)) { setContentView(R.layout.activity_main_large_screen); mIsLargeScreen = true; } else { setContentView(R.layout.activity_main); } initActionBar(savedInstanceState); SharedPreferences settings = Application.getPrefs(); double tempMinTime = Double.valueOf(settings.getString(getString(R.string.pref_key_gps_min_time), getString(R.string.pref_gps_min_time_default_sec))); minTime = (long) (tempMinTime * SECONDS_TO_MILLISECONDS); minDistance = Float.valueOf(settings.getString(getString(R.string.pref_key_gps_min_distance), getString(R.string.pref_gps_min_distance_default_meters))); if (settings.getBoolean(getString(R.string.pref_key_auto_start_gps), true)) { gpsStart(); } } @Override protected void onResume() { super.onResume(); if (GpsTestUtil.isRotationVectorSensorSupported(this)) { // Use the modern rotation vector sensors Sensor vectorSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); mSensorManager.registerListener(this, vectorSensor, 16000); // ~60hz } else { // Use the legacy orientation sensors Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION); if (sensor != null) { mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME); } } if (!mService.isProviderEnabled(LocationManager.GPS_PROVIDER)) { promptEnableGps(); } /** * Check preferences to see how they should be initialized */ SharedPreferences settings = Application.getPrefs(); checkKeepScreenOn(settings); checkTimeAndDistance(settings); checkTutorial(settings); checkTrueNorth(settings); } @Override protected void onPause() { mSensorManager.unregisterListener(this); super.onPause(); } /** * Ask the user if they want to enable GPS */ private void promptEnableGps() { new AlertDialog.Builder(this).setMessage(getString(R.string.enable_gps_message)) .setPositiveButton(getString(R.string.enable_gps_positive_button), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); startActivity(intent); } }) .setNegativeButton(getString(R.string.enable_gps_negative_button), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { } }) .show(); } private void checkTimeAndDistance(SharedPreferences settings) { double tempMinTimeDouble = Double .valueOf(settings.getString(getString(R.string.pref_key_gps_min_time), "1")); long minTimeLong = (long) (tempMinTimeDouble * SECONDS_TO_MILLISECONDS); if (minTime != minTimeLong || minDistance != Float .valueOf(settings.getString(getString(R.string.pref_key_gps_min_distance), "0"))) { // User changed preference values, get the new ones minTime = minTimeLong; minDistance = Float.valueOf(settings.getString(getString(R.string.pref_key_gps_min_distance), "0")); // If the GPS is started, reset the location listener with the new values if (mStarted && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { mService.requestLocationUpdates(mProvider.getName(), minTime, minDistance, this); Toast.makeText(this, String.format(getString(R.string.gps_set_location_listener), String.valueOf(tempMinTimeDouble), String.valueOf(minDistance)), Toast.LENGTH_SHORT).show(); } } } private void checkTutorial(SharedPreferences settings) { if (!settings.getBoolean(getString(R.string.pref_key_showed_v2_tutorial), false)) { // If GPS is started, stop to clear the screen (we will start it again at the end of this method) boolean lastStartState = mStarted; if (mStarted) { gpsStop(); } // Show the user a tutorial on using the ActionBar button to start/stop GPS, // either on first execution or when the user choose the option in the Preferences mOptions.shotType = ShowcaseView.TYPE_ONE_SHOT; mOptions.block = false; mOptions.hideOnClickOutside = true; mOptions.noButton = true; // TODO View homeButton = findViewById(android.R.id.home); if (homeButton == null) { int homeId = getResources().getIdentifier("abs__home", "id", getPackageName()); if (homeId != 0) { homeButton = findViewById(homeId); } } if (homeButton != null) { sv = ShowcaseView.insertShowcaseViewWithType(ShowcaseView.ITEM_ACTION_ITEM, R.id.gps_switch, this, R.string.showcase_gps_on_off_title, R.string.showcase_gps_on_off_message, mOptions); sv.show(); } SharedPreferences.Editor editor = Application.getPrefs().edit(); editor.putBoolean(getString(R.string.pref_key_showed_v2_tutorial), true); editor.commit(); if (lastStartState) { Handler h = new Handler(); // Restart the GPS, if it was previously started, with a slight delay to allow the UI to clear // and allow the tutorial to be clearly visible h.postDelayed(new Runnable() { public void run() { gpsStart(); } }, 500); } } } private void checkKeepScreenOn(SharedPreferences settings) { if (mViewPager != null) { if (settings.getBoolean(getString(R.string.pref_key_keep_screen_on), true)) { mViewPager.setKeepScreenOn(true); } else { mViewPager.setKeepScreenOn(false); } } else { View v = findViewById(R.id.large_screen_layout); if (v != null && mIsLargeScreen) { if (settings.getBoolean(getString(R.string.pref_key_keep_screen_on), true)) { v.setKeepScreenOn(true); } else { v.setKeepScreenOn(false); } } } } private void checkTrueNorth(SharedPreferences settings) { mFaceTrueNorth = settings.getBoolean(getString(R.string.pref_key_true_north), true); } @Override protected void onDestroy() { mService.removeGpsStatusListener(this); if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) { mService.removeUpdates(this); } super.onDestroy(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.gps_menu, menu); initGpsSwitch(menu); return true; } private void initGpsSwitch(Menu menu) { MenuItem item = menu.findItem(R.id.gps_switch); if (item != null) { mSwitch = (org.jraf.android.backport.switchwidget.Switch) MenuItemCompat.getActionView(item); if (mSwitch != null) { // Initialize state of GPS switch before we set the listener, so we don't double-trigger start or stop mSwitch.setChecked(mStarted); // Set up listener for GPS on/off switch, since custom menu items on Action Bar don't play // well with ABS and we can't handle in onOptionsItemSelected() mSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { // Turn GPS on or off if (!isChecked && mStarted) { gpsStop(); } else { if (isChecked && !mStarted) { gpsStart(); } } } }); } } } @Override public boolean onPrepareOptionsMenu(Menu menu) { MenuItem item; item = menu.findItem(R.id.send_location); if (item != null) { item.setVisible(mLastLocation != null); } return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { boolean success; // Handle menu item selection switch (item.getItemId()) { case R.id.gps_switch: // Do nothing - this is handled by a separate listener added in onCreateOptionsMenu() return true; case R.id.delete_aiding_data: // If GPS is currently running, stop it boolean lastStartState = mStarted; if (mStarted) { gpsStop(); } success = sendExtraCommand(getString(R.string.delete_aiding_data_command)); if (success) { Toast.makeText(this, getString(R.string.delete_aiding_data_success), Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, getString(R.string.delete_aiding_data_failure), Toast.LENGTH_SHORT).show(); } if (lastStartState) { Handler h = new Handler(); // Restart the GPS, if it was previously started, with a slight delay, // to refresh the assistance data h.postDelayed(new Runnable() { public void run() { gpsStart(); } }, 500); } return true; case R.id.send_location: sendLocation(); return true; case R.id.force_time_injection: success = sendExtraCommand(getString(R.string.force_time_injection_command)); if (success) { Toast.makeText(this, getString(R.string.force_time_injection_success), Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, getString(R.string.force_time_injection_failure), Toast.LENGTH_SHORT).show(); } return true; case R.id.force_xtra_injection: success = sendExtraCommand(getString(R.string.force_xtra_injection_command)); if (success) { Toast.makeText(this, getString(R.string.force_xtra_injection_success), Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, getString(R.string.force_xtra_injection_failure), Toast.LENGTH_SHORT).show(); } return true; case R.id.menu_settings: // Show settings menu startActivity(new Intent(this, Preferences.class)); default: return super.onOptionsItemSelected(item); } } public void onLocationChanged(Location location) { mLastLocation = location; updateGeomagneticField(); // Reset the options menu to trigger updates to action bar menu items invalidateOptionsMenu(); for (GpsTestListener listener : mGpsTestListeners) { listener.onLocationChanged(location); } } public void onStatusChanged(String provider, int status, Bundle extras) { for (GpsTestListener listener : mGpsTestListeners) { listener.onStatusChanged(provider, status, extras); } } public void onProviderEnabled(String provider) { for (GpsTestListener listener : mGpsTestListeners) { listener.onProviderEnabled(provider); } } public void onProviderDisabled(String provider) { for (GpsTestListener listener : mGpsTestListeners) { listener.onProviderDisabled(provider); } } public void onGpsStatusChanged(int event) { mStatus = mService.getGpsStatus(mStatus); switch (event) { case GpsStatus.GPS_EVENT_STARTED: break; case GpsStatus.GPS_EVENT_STOPPED: break; case GpsStatus.GPS_EVENT_FIRST_FIX: int ttff = mStatus.getTimeToFirstFix(); if (ttff == 0) { mTtff = ""; } else { ttff = (ttff + 500) / 1000; mTtff = Integer.toString(ttff) + " sec"; } break; case GpsStatus.GPS_EVENT_SATELLITE_STATUS: // Stop progress bar after the first status information is obtained setSupportProgressBarIndeterminateVisibility(Boolean.FALSE); break; } // If the user is viewing the tutorial, we don't want to clutter the status screen, so return if (sv != null && sv.isShown()) { return; } for (GpsTestListener listener : mGpsTestListeners) { listener.onGpsStatusChanged(event, mStatus); } } @TargetApi(Build.VERSION_CODES.GINGERBREAD) @Override public void onSensorChanged(SensorEvent event) { double orientation = Double.NaN; double tilt = Double.NaN; switch (event.sensor.getType()) { case Sensor.TYPE_ROTATION_VECTOR: // Modern rotation vector sensors if (!mTruncateVector) { try { SensorManager.getRotationMatrixFromVector(mRotationMatrix, event.values); } catch (IllegalArgumentException e) { // On some Samsung devices, an exception is thrown if this vector > 4 (see #39) // Truncate the array, since we can deal with only the first four values Log.e(TAG, "Samsung device error? Will truncate vectors - " + e); mTruncateVector = true; // Do the truncation here the first time the exception occurs getRotationMatrixFromTruncatedVector(event.values); } } else { // Truncate the array to avoid the exception on some devices (see #39) getRotationMatrixFromTruncatedVector(event.values); } int rot = getWindowManager().getDefaultDisplay().getRotation(); switch (rot) { case Surface.ROTATION_0: // No orientation change, use default coordinate system SensorManager.getOrientation(mRotationMatrix, mValues); // Log.d(TAG, "Rotation-0"); break; case Surface.ROTATION_90: // Log.d(TAG, "Rotation-90"); SensorManager.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_Y, SensorManager.AXIS_MINUS_X, mRemappedMatrix); SensorManager.getOrientation(mRemappedMatrix, mValues); break; case Surface.ROTATION_180: // Log.d(TAG, "Rotation-180"); SensorManager.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_MINUS_X, SensorManager.AXIS_MINUS_Y, mRemappedMatrix); SensorManager.getOrientation(mRemappedMatrix, mValues); break; case Surface.ROTATION_270: // Log.d(TAG, "Rotation-270"); SensorManager.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_MINUS_Y, SensorManager.AXIS_X, mRemappedMatrix); SensorManager.getOrientation(mRemappedMatrix, mValues); break; default: // This shouldn't happen - assume default orientation SensorManager.getOrientation(mRotationMatrix, mValues); // Log.d(TAG, "Rotation-Unknown"); break; } orientation = Math.toDegrees(mValues[0]); // azimuth tilt = Math.toDegrees(mValues[1]); break; case Sensor.TYPE_ORIENTATION: // Legacy orientation sensors orientation = event.values[0]; break; default: // A sensor we're not using, so return return; } // Correct for true north, if preference is set if (mFaceTrueNorth && mGeomagneticField != null) { orientation += mGeomagneticField.getDeclination(); // Make sure value is between 0-360 orientation = MathUtils.mod((float) orientation, 360.0f); } for (GpsTestListener listener : mGpsTestListeners) { listener.onOrientationChanged(orientation, tilt); } } @TargetApi(Build.VERSION_CODES.GINGERBREAD) private void getRotationMatrixFromTruncatedVector(float[] vector) { System.arraycopy(vector, 0, mTruncatedRotationVector, 0, 4); SensorManager.getRotationMatrixFromVector(mRotationMatrix, mTruncatedRotationVector); } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } private void updateGeomagneticField() { mGeomagneticField = new GeomagneticField((float) mLastLocation.getLatitude(), (float) mLastLocation.getLongitude(), (float) mLastLocation.getAltitude(), mLastLocation.getTime()); } private void sendLocation() { if (mLastLocation != null) { Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", "", null)); String location = "http://maps.google.com/maps?geocode=&q=" + Double.toString(mLastLocation.getLatitude()) + "," + Double.toString(mLastLocation.getLongitude()); intent.putExtra(Intent.EXTRA_TEXT, location); startActivity(intent); } } @Override public void onTabSelected(android.support.v7.app.ActionBar.Tab tab, FragmentTransaction ft) { // When the given tab is selected, switch to the corresponding page in // the ViewPager. if (mViewPager != null) { mViewPager.setCurrentItem(tab.getPosition()); } } @Override public void onTabUnselected(android.support.v7.app.ActionBar.Tab tab, FragmentTransaction ft) { } @Override public void onTabReselected(android.support.v7.app.ActionBar.Tab tab, FragmentTransaction ft) { } private void initActionBar(Bundle savedInstanceState) { // Set up the action bar. final android.support.v7.app.ActionBar actionBar = getSupportActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); actionBar.setTitle(getApplicationContext().getText(R.string.app_name)); // If we don't have a large screen, set up the tabs using the ViewPager if (!mIsLargeScreen) { // page adapter contains all the fragment registrations mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); // Set up the ViewPager with the sections adapter. mViewPager = (ViewPagerMapBevelScroll) findViewById(R.id.pager); mViewPager.setAdapter(mSectionsPagerAdapter); mViewPager.setOffscreenPageLimit(2); // When swiping between different sections, select the corresponding // tab. We can also use ActionBar.Tab#select() to do this if we have a // reference to the Tab. mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { actionBar.setSelectedNavigationItem(position); } }); // For each of the sections in the app, add a tab to the action bar. for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) { // Create a tab with text corresponding to the page title defined by // the adapter. Also specify this Activity object, which implements // the TabListener interface, as the listener for when this tab is // selected. actionBar.addTab( actionBar.newTab().setText(mSectionsPagerAdapter.getPageTitle(i)).setTabListener(this)); } } } interface GpsTestListener extends LocationListener { public void gpsStart(); public void gpsStop(); public void onGpsStatusChanged(int event, GpsStatus status); public void onOrientationChanged(double orientation, double tilt); } /** * A {@link FragmentStatePagerAdapter} that returns a fragment corresponding to * one of the primary sections of the app. */ public class SectionsPagerAdapter extends FragmentStatePagerAdapter { public static final int NUMBER_OF_TABS = 3; // Used to set up TabListener // Constants for the different fragments that will be displayed in tabs, in numeric order public static final int GPS_STATUS_FRAGMENT = 0; public static final int GPS_MAP_FRAGMENT = 1; public static final int GPS_SKY_FRAGMENT = 2; // Maintain handle to Fragments to avoid recreating them if one already // exists Fragment gpsStatus, gpsMap, gpsSky; public SectionsPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int i) { switch (i) { case GPS_STATUS_FRAGMENT: if (gpsStatus == null) { gpsStatus = new GpsStatusFragment(); } return gpsStatus; case GPS_MAP_FRAGMENT: if (gpsMap == null) { gpsMap = new GpsMapFragment(); } return gpsMap; case GPS_SKY_FRAGMENT: if (gpsSky == null) { gpsSky = new GpsSkyFragment(); } return gpsSky; } return null; // This should never happen } @Override public int getCount() { return NUMBER_OF_TABS; } @Override public CharSequence getPageTitle(int position) { switch (position) { case GPS_STATUS_FRAGMENT: return getString(R.string.gps_status_tab); case GPS_MAP_FRAGMENT: return getString(R.string.gps_map_tab); case GPS_SKY_FRAGMENT: return getString(R.string.gps_sky_tab); } return null; // This should never happen } } }