FusedLocationProviderClient在空闲情况下停止提供位置

时间:2018-10-21 04:49:56

标签: android service location broadcastreceiver fusedlocationproviderclient

我正在使用FusedLocationProviderClient开发位置跟踪应用程序。我有一个后台服务,每5分钟跟踪一次手机的位置。

一切正常,但是一旦手机进入空闲状态,则在3到4个小时后,后台服务将停止定位。当用户解锁手机时,跟踪会再次开始。

有人可以指导我导致问题的原因吗?

  

LocationUpdatesBroadcastReceiver

(new WebDriverWait(driver, 30)).until(ExpectedConditions.refreshed(ExpectedConditions.visibilityOf(element)));
  

MainActivity

    THIS CODE IS DEPENDENT UPON THE ETHERNET LIBRARY 2.0.0, WHICH IS AVAILABLE 
    FOR DOWNLOAD FROM <https://www.arduinolibraries.info/libraries/ethernet2>.
    ADDITIONAL DOCUMENTATION IS AVIALABLE AT <https://www.pjrc.com/arduino-ethernet-library-2-0-0/>, 
    <https://www.arduino.cc/en/Reference/> AND <https://www.arduino.cc/reference/en/language/functions/communication/stream/>.

    -------------------------------------------------------------------------------------------
*/

#include <SPI.h>
#include <TextFinder.h>
#include <Dhcp.h>
#include <Dns.h>
#include <Ethernet.h>
#include <EthernetUdp.h>

#define kBUILD_TO_DEBUG

const int   kSPI_CLK_PIN                    =   13;
const int   kSPI_MISO_PIN                   =   12;
const int   kSPI_MOSI_PIN                   =   11;
const int   kETHERNET_CS_PIN                =   10;

const int   kSPI_DEVICE_DISABLED            =   HIGH;
const int   kSPI_DEVICE_ENABLED             =   LOW;
const int   kRD382_RESET_ASSERTED           =   HIGH;
const int   kRD382_RESET_NEGATED            =   LOW;

enum {
    kPUBLIC_IP_ADDRESS,
    kLOCAL_IP_ADDRESS
} IP_ADDRESS_TYPES;

enum {
    kSTATE_POSITION_WAIT_FOR_LINK = 0,
    kSTATE_POSITION_GET_DHCP,
    kSTATE_POSITION_GET_IP,
    kSTATE_POSITION_RUN_TIMER,
    kSTATE_POSITION_PERFORM_TASK_ON_ADDRESS_CHANGE,
    kSTATE_POSITION_SEND_REPORT_ON_ADDRESS_CHANGE,
    kSTATE_POSITION_FATAL_ERROR
} STATE_POSITIONS;

typedef struct {
    IPAddress               public_ip_address;
    IPAddress               local_ip_address;
    unsigned long int       currentTime;
    unsigned long int       resetcount;
    unsigned int            millisTimer;
    int                     link_status;
    uint8_t                 secondsTimer;
    uint8_t                 minutesTimer;
    uint8_t                 state_position;
} GLOBALS;

const int   kTIMER_INIT_MILLISECONDS                    =   999;
const int   kTIMER_INIT_SECONDS                         =    59;
const int   kTIMER_INIT_MINUTES                         =     4;
const int   kMILLIS_ONE_SECOND_DELAY                    =   1000;

const int   kCONNECT_SUCCESS                            =      1;
const int   kCONNECT_TIMED_OUT                          =     -1;
const int   kCONNECT_INVALID_SERVER                     =     -2;
const int   kCONNECT_TRUNCATED                          =     -3;
const int   kCONNECT_INVALID_RESPONSE                   =     -4;

const int   kMAC_UNICAST_MULTICAST_BIT_ADDRESS          =   0;
const int   kMAC_UNICAST                                =   0;
const int   kMAC_UNICAST_AND_MASK                       =   ~( 1 << kMAC_UNICAST_MULTICAST_BIT_ADDRESS );
const int   kMAC_LOCALLY_ADMINISTERED_BIT_ADDRESS       =   1;
const int   kMAC_LOCALLY_ADMINISTERED                   =   1;
const int   kMAC_LOCALLY_ADMINISTERED_OR_MASK           =   ( kMAC_LOCALLY_ADMINISTERED << kMAC_LOCALLY_ADMINISTERED_BIT_ADDRESS );
const int   kMAC_ADDRESS_MSB                            =   '0' & kMAC_UNICAST_AND_MASK | kMAC_LOCALLY_ADMINISTERED_OR_MASK;

//  If the Ethernet adapter has a MAC address, enter that MAC address into mac_address[].
const byte  mac_address[]                               =   {kMAC_ADDRESS_MSB, 'E', 'N', 'E', 'T', '0'};

/*
    If you would prefer to use your own page to support obtaining the public IP address, the 
    following HTML5 and PHP code can be used as the source for that page:

    <html><head><title>Current IP Check</title></head><body>Current IP Address: <?php echo $_SERVER['REMOTE_ADDR']; ?></body></html>

    Then change the addressing constants below as appropriate.
*/
const char          kSERVER_DOMAIN_NAME[]               =   "checkip.dyndns.org";
const char          kSERVER_PAGE_NAME[]                 =   "/";
const char          kSERVER_PORT_NUMBER                 =   80;
const char          kIP_QUERY_PAGE[]                    =   "GET checkip.dyndns.org ";
const char          ip_search_str[]                     =   "IP Address: ";

const signed int    kENET_SUCCESS                       =    1;
const signed int    kENET_TIMED_OUT                     =   -1;
const signed int    kENET_INVALID_SERVER                =   -2;
const signed int    kENET_TRUNCATED                     =   -3;
const signed int    kENET_INVALID_RESPONSE              =   -4;

const int           kDEFAULT_CONNECTION_TIMEOUT         =   3000;
const int           kETHERNET_TIMEOUT                   =      5;
const int           kIP_QUERY_MINIMUM_SIZE              =    244;   //  Assume length for public IP of 1.1.1.1
const long          kIP_QUERY_TIMEOUT                   =   (  5 * kMILLIS_ONE_SECOND_DELAY );  // seconds, expressed in milliseconds
const int           kNOTIFICATION_RETRY_COUNT_SEED      =     10;
const int           kSIZE_OF_IPV4_ADDRESS               =      4;

EthernetClient      ethernetClient;
TextFinder          textFinder ( ethernetClient, kETHERNET_TIMEOUT );

GLOBALS             globals;

/*  --------------------------------------------------------------------------------    */

void address_changed_task ( void )
{
    //  Insert code to be executed when the public IP address changes, or upon the 
    //  initial acquisition of the public IP address.
#ifdef kBUILD_TO_DEBUG                          //  {
    if ( Serial )
    {
        Serial.println ( "STATUS: address_changed_task () completed" );
    }
#endif                                          //  }   kBUILD_TO_DEBUG
}

/*  --------------------------------------------------------------------------------    */

void send_report ( void )
{
    //  Insert code to report status after handling a change in public IP address
#ifdef kBUILD_TO_DEBUG                          //  {
    if ( Serial )
    {
        Serial.println ( "STATUS: send_report () completed" );
    }
#endif                                          //  }   kBUILD_TO_DEBUG
}

/*  --------------------------------------------------------------------------------    */

void clear_ip_address ( uint8_t ip_address_type )
{
    for ( int index = 0; index < kSIZE_OF_IPV4_ADDRESS; index++ )
    {
        switch ( ip_address_type )
        {
            case kPUBLIC_IP_ADDRESS:    globals.public_ip_address[index] = 0;   break;
            case kLOCAL_IP_ADDRESS:     globals.local_ip_address[index] = 0;    break;
        }
    }
}

//  --------------------------------------------------------------------------------

void display_ip_address ( uint8_t ip_address_type )
{
#ifdef kBUILD_TO_DEBUG                          //  {
    if ( Serial )
    {
        switch ( ip_address_type )
        {
            case kPUBLIC_IP_ADDRESS:
            {
                Serial.print ( "Public IP Address: " );
                for ( int index = 0; index < kSIZE_OF_IPV4_ADDRESS; index++ )
                {
                    Serial.print ( globals.public_ip_address[index] );
                    if ( index < ( kSIZE_OF_IPV4_ADDRESS - 1 ) )
                    {
                        Serial.print ( "." );
                    }
                }
            }
            break;

            case kLOCAL_IP_ADDRESS:
            {
                Serial.print ( "Local IP Address:  " );
                for ( int index = 0; index < kSIZE_OF_IPV4_ADDRESS; index++ )
                {
                    Serial.print ( globals.local_ip_address[index] );
                    if ( index < ( kSIZE_OF_IPV4_ADDRESS - 1 ) )
                    {
                        Serial.print ( "." );
                    }
                }
            }
            break;
        }
        Serial.println ( "" );
    }
#endif                                          //  }   kBUILD_TO_DEBUG
}

/*  --------------------------------------------------------------------------------    */

void display_mac_address ( void )
{
#ifdef kBUILD_TO_DEBUG                          //  {
    uint8_t         field_count = ( sizeof ( mac_address ) / sizeof ( mac_address[0] ) );

    if ( Serial )
    {
        Serial.print ( "MAC Address:       " );
        for ( int index = 0; index < field_count; index++ )
        {
            Serial.print ( mac_address[index] );
            if ( index < ( field_count - 1 ) )
            {
                Serial.print ( "." );
            }
        }
        Serial.println ( "" );
    }
#endif                                          //  }   kBUILD_TO_DEBUG
}

/*  --------------------------------------------------------------------------------    */
/*
    A query to http://checkip.dyndns.org will return the following:

        HTTP/1.1 200 OK
        Content-Type: text/html
        Server: DynDNS-CheckIP/1.0
        Connection: close
        Cache-Control: no-cache
        Pragma: no-cache
        Content-Length: 105

        <html><head><title>Current IP Check</title></head><body>Current IP Address: 50.37.222.230</body></html>
*/

boolean get_public_ip_address ( void )
{
    unsigned long int   temp_timer = 0;
    unsigned int        retry_count = kNOTIFICATION_RETRY_COUNT_SEED;
    signed int          client_connected_result = kENET_SUCCESS;
    byte                public_ip_address[] = {0,0,0,0};
    int                 availableDataSize;
    boolean             found_ip_address = false;
    boolean             values_matched = true;
    boolean             all_zero = true;
    boolean             result = false;

    while ( !found_ip_address && ( 0 != retry_count ) )
    {
        ethernetClient.setConnectionTimeout ( kDEFAULT_CONNECTION_TIMEOUT );
        client_connected_result = ethernetClient.connect ( (const char*)kSERVER_DOMAIN_NAME, kSERVER_PORT_NUMBER );
        if ( kCONNECT_SUCCESS == client_connected_result )
        {
            ethernetClient.println ( kIP_QUERY_PAGE );
            temp_timer = kIP_QUERY_TIMEOUT;

            availableDataSize = ethernetClient.available ();
            while ( ( kIP_QUERY_MINIMUM_SIZE > availableDataSize ) && ( 0 != temp_timer ) ) {
                availableDataSize = ethernetClient.available ();
                delay ( 1 );
                if ( 0 < temp_timer ) { temp_timer--; }
            };

            if ( 0 != availableDataSize )
            {
                if ( textFinder.find ( (char*)ip_search_str ) )
                {
                    values_matched = true;
                    all_zero = true;
                    for ( int index = 0; index < kSIZE_OF_IPV4_ADDRESS; index++ )
                    {
                        public_ip_address[index] = textFinder.getValue ();

                        if ( globals.public_ip_address[index] != public_ip_address[index] )
                        {
                            values_matched = false;
                            globals.public_ip_address[index] = public_ip_address[index];
                        }

                        if ( 0 != public_ip_address[index] )
                        {
                            all_zero = false;
                        }
                    }

                    if ( values_matched || !all_zero ) { found_ip_address = true; }
                    if ( !values_matched && !all_zero ) { result = true; }
                }
            }
            ethernetClient.stop ();
        }

        if ( 0 != retry_count ) { retry_count--; }
    }

    return result;
}

/*  --------------------------------------------------------------------------------    */

boolean ip_address_is_zero ( uint8_t ip_address_type )
{
    boolean     result = true;

    for ( int index = 0; index < kSIZE_OF_IPV4_ADDRESS; index++ )
    {
        switch ( ip_address_type )
        {
            case kPUBLIC_IP_ADDRESS:    if ( 0 != globals.public_ip_address[index] ) { result = false; }    break;
            case kLOCAL_IP_ADDRESS:     if ( 0 != globals.local_ip_address[index] ) { result = false; }     break;
        }
    }

    return result;
}

/*  --------------------------------------------------------------------------------    */

void setup ()
{
    globals.state_position = kSTATE_POSITION_WAIT_FOR_LINK;

#ifdef kBUILD_TO_DEBUG                          //  {
    Serial.begin ( 115200 );
    while ( !Serial ) {}
#endif                                          //  }   kBUILD_TO_DEBUG

    clear_ip_address ( kPUBLIC_IP_ADDRESS );
    clear_ip_address ( kLOCAL_IP_ADDRESS );

    pinMode ( kETHERNET_CS_PIN, OUTPUT );
    digitalWrite ( kETHERNET_CS_PIN, kSPI_DEVICE_DISABLED );

    display_mac_address ();

    /*
        Note that the following execution of Ethernet.begin ( mac ) will attempt to obtain 
        a local IP address via DHCP.  If the Ethernet cable is not attached, the 
        Ethernet.begin method will timeout after 60-seconds.  Aside from delaying 
        the completion of setup (), this delay imposes no bad behavior.   The 
        Ethernet.hardwareStatus () method does not function until after Ethernet.begin 
        has executed so setup () invokes Ethernet.begin regardless of any status.

        It would be desirable to invoke Ethernet.hardwareStatus () to determine if 
        Ethernet.linkStatus () is supported, and then execute Ethernet.begin ( mac ) only 
        if the LINK is active (i.e. cable is attached) when the hardware supports such a 
        determination (a value of EthernetNoHardware is returned).  The current Ethernet 
        library does not support this sequence (at least using a W5500 device).  If this 
        were possible, the invoking of Ethernet.begin ( mac ) would simply defer execution 
        to the state machine and avoid execution in setup ().
    */

    Ethernet.begin ( (byte*)mac_address );
}

/*  --------------------------------------------------------------------------------    
    The STATE MACHINE will detect attachment and detachment of the ethernet cable, 
    and initiate IP polling upon attachment of the cable.  IP Polling will be 
    suspended when the ethernet cable is detached.  For the W5100, where no link 
    (cable) detection is supported, the STATE MACHINE will act as if the ethernet 
    cable is always attached.

    Nominal state machine execution occurs at a minimum of 1-second intervals, with 
    the interval being extended by any task execution time.
*/

void    state_machine ( void )
{
    int         link_on_status = Unknown;
    uint8_t     current_state_position = globals.state_position;

    switch ( Ethernet.hardwareStatus () )
    {
        case EthernetNoHardware:    globals.state_position = kSTATE_POSITION_FATAL_ERROR;   break;
        case EthernetW5100:         link_on_status = LinkON;                                break;
        case EthernetW5200:         link_on_status = Ethernet.linkStatus ();                break;
        case EthernetW5500:         link_on_status = Ethernet.linkStatus ();                break;
    }

    switch ( globals.state_position )
    {
        case kSTATE_POSITION_WAIT_FOR_LINK:
        {
            /*
                This is the initial state position.  Global variables are initialized to prepare for proper 
                checks to occur once the ethernet link is determined to be active.
            */
            globals.minutesTimer = 0;
            globals.secondsTimer = 0;

            if ( !ip_address_is_zero ( kLOCAL_IP_ADDRESS ) )
            {
                clear_ip_address ( kPUBLIC_IP_ADDRESS );
                clear_ip_address ( kLOCAL_IP_ADDRESS );
                display_ip_address ( kPUBLIC_IP_ADDRESS );
                display_ip_address ( kLOCAL_IP_ADDRESS );
            }

            if ( LinkON == link_on_status )
            {
                globals.state_position = kSTATE_POSITION_GET_DHCP;
            }
        }
        break;

        case kSTATE_POSITION_GET_DHCP:
        {
            /*
                Upon attachment of the Ethernet cable, acquire a new DHCP address.  Execution of the 
                Ethernet.begin ( mac ) method may seem redundant, but occurs in case the cable has been 
                unplugged for sufficient time that the DHCP lease has expired.  It is possible that a 
                new address is required.
            */
            if ( LinkON == link_on_status )
            {
                Ethernet.begin ( (byte*)mac_address );
                globals.local_ip_address = Ethernet.localIP ();
                if ( !ip_address_is_zero ( kLOCAL_IP_ADDRESS ) )
                {
                    display_ip_address ( kLOCAL_IP_ADDRESS );
                    globals.state_position = kSTATE_POSITION_GET_IP;
                }
            }
            else if (  LinkOFF == link_on_status )
            {
                globals.state_position = kSTATE_POSITION_WAIT_FOR_LINK;
            }
        }
        break;

        case kSTATE_POSITION_GET_IP:
        {
            /*
                This state position obtains the public IP address by issuing a query to 'checkip.dyndns.org'.  
                The invoked function will parse the returned data to obtain the public IP address.
            */
            if ( LinkON == link_on_status )
            {
                if ( get_public_ip_address () )
                {
                    display_ip_address ( kPUBLIC_IP_ADDRESS );
                    globals.state_position = kSTATE_POSITION_PERFORM_TASK_ON_ADDRESS_CHANGE;
                }
                else
                {
                    globals.state_position = kSTATE_POSITION_RUN_TIMER;
                }
                Ethernet.maintain ();
            }
            else if (  LinkOFF == link_on_status )
            {
                globals.state_position = kSTATE_POSITION_WAIT_FOR_LINK;
            }
        }
        break;

        case kSTATE_POSITION_RUN_TIMER:
        {
            /*
                This state position checks whether it is time to check if the public IP address has changed.
            */
            if ( LinkON == link_on_status )
            {
                if ( 0 == globals.secondsTimer ) { globals.secondsTimer = kTIMER_INIT_SECONDS; }
                if ( 0 == globals.minutesTimer ) { globals.minutesTimer = kTIMER_INIT_MINUTES; }

                globals.secondsTimer--;
                if ( 0 == globals.secondsTimer )
                {
                    globals.minutesTimer--;
                    if ( 0 == globals.minutesTimer )
                    {
                        globals.state_position = kSTATE_POSITION_GET_IP;
                    }
                    globals.secondsTimer = kTIMER_INIT_SECONDS;
                }
                Ethernet.maintain ();
            }
            else if (  LinkOFF == link_on_status )
            {
                globals.state_position = kSTATE_POSITION_WAIT_FOR_LINK;
            }
        }
        break;

        case kSTATE_POSITION_PERFORM_TASK_ON_ADDRESS_CHANGE:
        {
            /*
                This state position will invoke the function to handle a change to the public IP address, 
                or upon initial acquisition of the public IP address (either on start up or when the 
                ethernet cable is attached).
            */
            if ( LinkON == link_on_status )
            {
                address_changed_task ();
                globals.state_position = kSTATE_POSITION_SEND_REPORT_ON_ADDRESS_CHANGE;
                Ethernet.maintain ();
            }
            else if (  LinkOFF == link_on_status )
            {
                globals.state_position = kSTATE_POSITION_WAIT_FOR_LINK;
            }
        }
        break;

        case kSTATE_POSITION_SEND_REPORT_ON_ADDRESS_CHANGE:
        {
            /*
                This state position will invoke the function to report completion of handling a change to 
                the public IP address.
            */
            if ( LinkON == link_on_status )
            {
                send_report ();
                globals.state_position = kSTATE_POSITION_RUN_TIMER;
                Ethernet.maintain ();
            }
            else if (  LinkOFF == link_on_status )
            {
                globals.state_position = kSTATE_POSITION_WAIT_FOR_LINK;
            }
        }
        break;

        case kSTATE_POSITION_FATAL_ERROR:
        {
            /*
                This state machine requires Ethernet hardware that can report the ethernet link status.  If the 
                hardware lacks this support, this state is entered and purposefully hangs.
            */
#ifdef kBUILD_TO_DEBUG                          //  {
            if ( Serial ) { Serial.println ( "FATAL ERROR: Ethernet hardware NOT FOUND" ); }
#endif                                          //  }   kBUILD_TO_DEBUG
            while ( true ) {};
        }
        break;
    }
}

/*  --------------------------------------------------------------------------------    */
/*
    State machine execution occurs at a minimum interval of 1000 milliseconds.
*/

void loop ()
{
    unsigned long int   currentTime = millis ();

    if ( globals.currentTime != currentTime )
    {
        globals.currentTime = currentTime;

        if ( ( 0 == globals.millisTimer ) || ( kTIMER_INIT_MILLISECONDS < globals.millisTimer ) )
        {
            globals.millisTimer = kTIMER_INIT_MILLISECONDS;
        }

        globals.millisTimer--;
        if ( 0 == globals.millisTimer ) 
        {
            state_machine ();
            globals.millisTimer = kTIMER_INIT_MILLISECONDS;
        }
    }
}

0 个答案:

没有答案