Google Maps API V2: значок GPS не отображается

В моем приложении я недавно обновил Карты Google с версии 1 до версии 2. Теперь, с HTC One S (Android 4.1.1), когда я включаю GPS и вхожу в действие карты, приложение распознает, что GPS включен, но его значок не появляется, и приложение не может найти мое местоположение.< br> На таких устройствах, как Samsung Galaxy Y (Android 2.3), карта работает без проблем.
На других, таких как Samsung Galaxy S2 (Android 4.1.2), HTC Wildfire (Android 2.3), значок GPS не появляется, но приложения определяет мое местоположение.
Где я не прав?

Класс:

public class CercaPuntoVendita extends FragmentActivity implements OnMarkerClickListener, LocationSource, LocationListener {

    // Identificatore del messaggio della Map
    private final static int MAP_MESSAGE_ID = 1;

    // Identificatore della ProgressBar
    private final static int PROGRESS_DIALOG_ID = 1;

    // Riferimento alla Map
    private GoogleMap map;

    // Riferimento alle UiSettings
    private UiSettings uis;

    // Riferimento al GeoCoder
    private Geocoder geocoder;

    // Riferimento alla EditText
    private EditText inputName;

    // Livello di Zoom
    private int nMetriDiametroCitta = 10000;
    private int nMetriDiametroVia = 1500;

    //Riferimento al MapController
    public static MapController mapController;  

    //Otteniamo il riferimento al LocationManager
    private LocationManager myLocationManager = null;
    private OnLocationChangedListener myLocationListener = null;
    private Criteria myCriteria;

    private PuntiVendita overlays = null;

    private Context ctx = this;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Mettiamo la View a tutto schermo
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        // Visualizziamo la Map
        setContentView(R.layout.cerca_punto_vendita);

        // Gestione font
        Button btnSearch = (Button) findViewById(R.id.searchButton);
        Typeface tf = Typeface.createFromAsset(ctx.getAssets(), "fonts/CRAI_regular.ttf");
        Utils.setFontMultiple(tf, btnSearch);

        // Set up della map
        setUpMapIfNeeded();

        // Riferimento al campo di testo
        inputName = (EditText)findViewById(R.id.addressName);

        // Otteniamo il riferimento al geocoder
        geocoder = new Geocoder(this,Locale.ITALY);

        // Otteniamo il riferimento al location manager
        myLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        // Verifichiamo se il GPS è abilitato altrimenti avvisiamo l'utente
        if(!myLocationManager.isProviderEnabled("gps")) {
            Utils.showWarningDialog(this, "GPS è attualmente disabilitato. E' possibile abilitarlo dal menu impostazioni.");
        }

        // muovo la mappa su Roma
        map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(41.893, 12.482), calculateZoomLevel(nMetriDiametroCitta)));
    }

    @Override
    public void onPause() {
        super.onPause();

        map.setLocationSource(null);
        myLocationManager.removeUpdates(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        setUpMapIfNeeded();

        map.setMyLocationEnabled(true);
        uis = map.getUiSettings();
        uis.setMyLocationButtonEnabled(false);
        myCriteria = new Criteria();
        myCriteria.setAccuracy(Criteria.ACCURACY_COARSE);
        myLocationManager = (LocationManager)getSystemService(LOCATION_SERVICE);

        // Verifichiamo se il GPS è abilitato altrimenti avvisiamo l'utente
        if(myLocationManager.isProviderEnabled("gps")) {
            try {
                Location loc = myLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(loc.getLatitude(), loc.getLongitude()), calculateZoomLevel(nMetriDiametroVia))); 
            } catch (NullPointerException e) {
            }

            //Register for location updates using a Criteria, and a callback on the specified looper thread.
            myLocationManager.requestLocationUpdates(
              0L,    //minTime
              0.0f,    //minDistance
              myCriteria,  //criteria
              this,    //listener
              null);   //looper

            //Replaces the location source of the my-location layer.
            map.setLocationSource(this);
        }
        //myLocationManager.getProviders(true); 
    }   

    public static double getRound(double x, int digits){
        double powerOfTen = Math.pow(10, digits);
        return (Math.round(x * powerOfTen) / powerOfTen);
    }

    /**
     * Permette di iniziare la ricerca
     * 
     * @param button
     *            Riferimento al button
     */
    public void searchPlace(View button) {
        hideSoftInput();

        Thread searchThread = new Thread("SearchThread") {

            @Override
            public void run() {
                // Otteniamo il messaggio
                Message message = mapHandler.obtainMessage();
                // Utilizziamo il Geocoder per fare la ricerca
                try {
                    List<Address> risultati = geocoder.getFromLocationName(inputName.getText().toString().trim(), 1);
                    // Se c'e' qualcosa lo notifichiamo
                    if (risultati != null && risultati.size() > 0) {
                        message.obj = risultati.get(0);
                        mapHandler.sendMessage(message);
                    } else {
                        runOnUiThread(new Runnable() {                
                            public void run() {
                                Utils.msg(CercaPuntoVendita.this, "Nessun risultato trovato");
                            }
                        });
                    }
                } catch (IOException e) {
                    // Non facciamo nulla ma arriva il messaggio vuoto
                    mapHandler.sendEmptyMessage(MAP_MESSAGE_ID);
                } finally {
                    dismissDialog(PROGRESS_DIALOG_ID);
                }
            }

        };
        // Visualizziamo la progressDialog
        showDialog(PROGRESS_DIALOG_ID);
        // Facciamo partire il Thread
        searchThread.start();
    }

    private final Handler mapHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // Si ottengono le informazioni se presenti sulla posizione
            if (msg != null && msg.obj != null) {
                // Estraiamo le informazioni di posizione
                try { 
                    Address address = (Address)msg.obj;
                    Log.d("CercaPuntoVendita.this", "" + address.getLocality());
                    GeoPoint pointToGo = new GeoPoint((int)(address.getLatitude()*1000000),(int)(address.getLongitude()*1000000));
                    float dZoom = 0;
                    if (address.getLocality().equalsIgnoreCase(inputName.getText().toString().trim())) {
                        // se la locality è uguale alla stringa di ricerca, si tratta di una citta'
                        dZoom = calculateZoomLevel(nMetriDiametroCitta);
                    } else {
                        dZoom = calculateZoomLevel(nMetriDiametroVia);
                    }
                    map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(address.getLatitude(), address.getLongitude()), dZoom));
                } catch (NullPointerException ex) {
                    Utils.msg(CercaPuntoVendita.this, "Nessun risultato trovato");
                    Log.w("Punti Vendita - Cerca", (ex.getMessage() == null)?"address = null":ex.getMessage()); 
                }
            } else {
                Utils.msg(CercaPuntoVendita.this, "Nessun risultato trovato");
            }
            Log.i("GEOCODER", "" + msg);
            if (msg != null) {
                Log.i("GEOCODER", "" + msg.obj);
            }
        }
    };

    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
        case PROGRESS_DIALOG_ID:
            ProgressDialog progressDialog = new ProgressDialog(this, ProgressDialog.STYLE_SPINNER);
            progressDialog.setIndeterminate(true);
            progressDialog.setTitle("Cerca Punti Vendita");
            progressDialog.setMessage("Cercando...");
            return progressDialog;
        default:
            return null;
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Menù di gestione modalità di visualizzazione che, per renderle checkable le inseriamo in un sottomenu
        SubMenu mapSubMenu = menu.addSubMenu("Modalità Mappa");
        mapSubMenu.setIcon(android.R.drawable.ic_menu_mapmode);
        int firstItem = Menu.FIRST;
        MenuItem trafficItem = mapSubMenu.add(1, firstItem, firstItem, "Traffic");
        trafficItem.setCheckable(true);
        trafficItem.setChecked(false);
        MenuItem satelliteItem = mapSubMenu.add(1, firstItem + 1, firstItem + 1, "Satellite");
        satelliteItem.setCheckable(true);
        trafficItem.setChecked(false);
        // Visualizziamo il menu
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Modifichiamo lo stato di quella selezionata
        item.setChecked(!item.isChecked());
        // Abilitiamo o meno l'opzione relativa
        switch (item.getItemId()) {
            case Menu.FIRST:
                map.setTrafficEnabled(item.isChecked());
                break;
            case Menu.FIRST + 1:
                if (item.isChecked())
                    map.setMapType(MAP_TYPE_SATELLITE);
                else
                    map.setMapType(MAP_TYPE_NORMAL);
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    protected boolean isRouteDisplayed() {
        return false;
    }

    private void hideSoftInput() {
        InputMethodManager inputManager = (InputMethodManager) CercaPuntoVendita.this.getSystemService(Context.INPUT_METHOD_SERVICE); 
        inputManager.hideSoftInputFromWindow(CercaPuntoVendita.this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
    }

    public boolean onMarkerClick(Marker mrk) {
        final ProgressDialog progressDialog = ProgressDialog.show(ctx, "", "Caricamento in corso.\nAttendere prego...");
        final String sSnippet = mrk.getSnippet();
        new Thread() {
            @Override
            public void run() {
                try {
                    sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                Intent intent = new Intent(ctx, PuntoVenditaDett.class);
                intent.putExtra("myPdvId", sSnippet);
                ctx.startActivity(intent);

                progressDialog.dismiss();
            }
        }.start();

        return true;
    }

    private void setUpMap() { 
        // Gestiamo gli Overlay
        Drawable starImg = getResources().getDrawable(R.drawable.logominicrai);
        if (overlays == null)
            overlays = new PuntiVendita(starImg, this);
        map.setOnMarkerClickListener(this);
        for (int i=0; i < overlays.size(); i++) {
            LatLng llPunto = new LatLng(overlays.getItem(i).getPoint().getLatitudeE6()/1E6, overlays.getItem(i).getPoint().getLongitudeE6()/1E6);

            map.addMarker(new MarkerOptions()
                .position(llPunto)
                //.title(name)
                .snippet(overlays.getItem(i).getSnippet())
                .icon(BitmapDescriptorFactory
                    .fromResource(R.drawable.logominicrai)));
        }
    }

    private void setUpMapIfNeeded() {
        // Do a null check to confirm that we have not already instantiated the map.
        if (map == null) {
            // Try to obtain the map from the SupportMapFragment.
            map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
            // Check if we were successful in obtaining the map.
            if (map != null) {
                setUpMap();
            }
        }
    }

    public void onLocationChanged(Location location) {
        if (myLocationListener != null) {
            myLocationListener.onLocationChanged(location);

            LatLng latlng = new LatLng(location.getLatitude(), location.getLongitude());
            map.animateCamera(CameraUpdateFactory.newLatLng(latlng));
        }
    }

    public void onProviderDisabled(String provider) {
        // TODO Auto-generated method stub

    }

    public void onProviderEnabled(String provider) {
        // TODO Auto-generated method stub

    }

    public void onStatusChanged(String provider, int status, Bundle extras) {
        // TODO Auto-generated method stub

    }

    public void activate(OnLocationChangedListener listener) {
        myLocationListener = listener;
    }

    public void deactivate() {
        myLocationListener = null;
    }
}

Манифест:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.gmaps"
    android:versionCode="2"
    android:versionName="2" >

    <uses-sdk android:minSdkVersion="9" />

    <!-- Google Maps API V2 -->
    <permission
        android:name="com.example.gmaps.permission.MAPS_RECEIVE"
        android:protectionLevel="signature" />
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />
    <uses-permission android:name="com.example.gmaps.permission.MAPS_RECEIVE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />     

    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.FLASHLIGHT" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/icon"
        android:label="@string/app_name" >

        <activity
            android:name="com.fedrasoft.craiinforma.App"
            android:configChanges="orientation|keyboardHidden|keyboard"
            android:screenOrientation="portrait"
            android:launchMode="singleTask" >
            <!-- android:alwaysRetainTaskState="true" --> 
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity
            android:name="com.fedrasoft.craiinforma.CercaPuntoVendita"
            android:label="@string/title_activity_cerca_punto_vendita"
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name="CercaPuntoVendita" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

        <uses-library android:name="com.google.android.maps" />

        <!-- Google Maps API V2 -->
        <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="my key" /> 
    </application>

</manifest>

person Umberto    schedule 22.04.2013    source источник
comment
Вы не предоставляете достаточно подробностей. Вы установили MyLocationEnabled (true) в GoogleMap?   -  person Yaroslav Mytkalyk    schedule 22.04.2013
comment
@DoctororDrive Да, я установил.   -  person Umberto    schedule 22.04.2013
comment
Вы уверены, что GPS действительно включен на этом телефоне?   -  person tasomaniac    schedule 23.04.2013
comment
@tasomaniac Да, потому что я проверяю это в коде с помощью myLocationManager.isProviderEnabled(gps)   -  person Umberto    schedule 23.04.2013
comment
Может просто GPS недоступен (обновления не детит) и иконка не появляется из-за прошивки HTC? Вы пробовали Google Maps и проверяли, видите ли вы значок? Попробуйте приложение Fake GPS Location (из GooglePlay) для мгновенного определения местоположения.   -  person Yaroslav Mytkalyk    schedule 23.04.2013
comment
@DoctororDrive Я попробовал Карты Google, и GPS работает нормально, появляется значок   -  person Umberto    schedule 23.04.2013


Ответы (2)


Следуя совету @Nevermore, я решил проблему с реализацией OnMyLocationChangeListener вместо LocationSource и LocationListener.
Я изменил код следующим образом:

public class CercaPuntoVendita extends FragmentActivity implements OnMarkerClickListener, OnMyLocationChangeListener {
    //...
    public void onMyLocationChange(Location location) {
        mMap.animateCamera(
            CameraUpdateFactory.newLatLng(
                new LatLng(location.getLatitude(), location.getLongitude())));
    }
}
person Umberto    schedule 26.04.2013

Я обнаружил, что эта проблема зависит от инструкции:

map.setLocationSource(this);

Если я им не пользуюсь, GPS работает нормально, но не может «следить» за моим местоположением. Я должен поставить эту инструкцию таким образом, чтобы она всегда могла установить источник местоположения, даже когда я включаю GPS на лету...

person Umberto    schedule 24.04.2013
comment
В последнем выпуске представлен OnMyLocationChangeListener, поэтому вам не нужно реализовывать (и set) пользовательский LocationSource (и запросы на обновление местоположения вручную!) больше, чтобы следовать точке My Location. Вам только нужно включить слой моего местоположения через map.setMyLocationEnabled(true), map.setOnMyLocationChangeListener(this) и анимировать камеру в соответствующем обратном вызове, предоставляемом этим интерфейсом. - person Nevermore; 25.04.2013