Οι αισθητήρες Master του Android: υλικό, λογισμικό και πολυδιάστατο

Συγγραφέας: John Stephens
Ημερομηνία Δημιουργίας: 26 Ιανουάριος 2021
Ημερομηνία Ενημέρωσης: 5 Ιούλιος 2024
Anonim
Οι αισθητήρες Master του Android: υλικό, λογισμικό και πολυδιάστατο - Εφαρμογές
Οι αισθητήρες Master του Android: υλικό, λογισμικό και πολυδιάστατο - Εφαρμογές

Περιεχόμενο


Σήμερα, οι περισσότερες σύγχρονες συσκευές Android είναι εξοπλισμένες με μια δέσμη αισθητήρων.

Μπορείτε να χρησιμοποιήσετε αυτές τις πληροφορίες με πολλούς διαφορετικούς τρόπους - ανεξάρτητα από το αν παρακολουθούν επίπεδα φωτισμού, έτσι ώστε η εφαρμογή σας να μπορεί να προσαρμόσει αυτόματα τη φωτεινότητα ή το χρωματικό σχήμα της. επιτρέποντας στον χρήστη να αλληλεπιδράσει με το κινητό σας παιχνίδι χρησιμοποιώντας χειρονομίες όπως η κλίση της συσκευής του. ή χρησιμοποιώντας τον αισθητήρα εγγύτητας για να απενεργοποιήσετε αυτόματα τα συμβάντα αφής όποτε ο χρήστης κρατά τη συσκευή στο αυτί τους.

Σε αυτό το άρθρο, θα δημιουργήσουμε τρεις εφαρμογές που ανακτούν τα δεδομένα φωτός, εγγύτητας και κίνησης από μια σειρά αισθητήρων υλικού και λογισμικού. Θα παρακολουθήσουμε επίσης αυτούς τους αισθητήρες Android σε πραγματικό χρόνο, έτσι ώστε η εφαρμογή σας να έχει πάντα πρόσβαση στις πιο πρόσφατες πληροφορίες.

Μέχρι το τέλος αυτού του άρθρου, θα μάθετε πώς μπορείτε να εξαγάγετε ένα κομμάτι δεδομένων από έναν αισθητήρα Android και πώς να χειρίζεστε αισθητήρες που παρέχουν τα δεδομένα τους με τη μορφή ενός πολυδιάστατου πίνακα.


Τι αισθητήρες Android μπορώ να χρησιμοποιήσω;

Οι αισθητήρες Android μπορούν να χωριστούν στις ακόλουθες κατηγορίες:

  • Περιβαλλοντικοί αισθητήρες. Αυτά μετρούν τις περιβαλλοντικές συνθήκες, όπως η θερμοκρασία του αέρα, η πίεση, η υγρασία και τα επίπεδα φωτισμού περιβάλλοντος.

  • Αισθητήρες θέσης. Αυτή η κατηγορία περιλαμβάνει αισθητήρες που μετρούν τη φυσική θέση της συσκευής, όπως αισθητήρες προσέγγισης και αισθητήρες γεωμαγνητικού πεδίου.
    Αισθητήρες κίνησης. Αυτοί οι αισθητήρες μετρούν την κίνηση της συσκευής και περιλαμβάνουν επιταχυνσιόμετρα, αισθητήρες βαρύτητας, γυροσκόπια και αισθητήρες διανύσματος περιστροφής.

Επιπλέον, οι αισθητήρες μπορούν να είναι είτε:

  • Βασισμένο στο υλικό. Αυτά είναι φυσικά συστατικά που είναι ενσωματωμένα στη συσκευή και μετρούν άμεσα τις συγκεκριμένες ιδιότητες, όπως η επιτάχυνση ή η ισχύς των γύρω γεωμαγνητικών πεδίων.
  • Βασισμένο στο λογισμικό, μερικές φορές γνωστό ως εικονικοί αισθητήρες ή σύνθετοι αισθητήρες. Αυτές συνήθως συγκεντρώνουν δεδομένα από πολλούς αισθητήρες που βασίζονται σε υλικό. Προς το τέλος αυτού του άρθρου θα συνεργαστούμε με τον αισθητήρα διάνυσμα περιστροφής, ο οποίος είναι ένας αισθητήρας λογισμικού που συνδυάζει δεδομένα από το επιταχυνσιόμετρο της συσκευής, το μαγνητόμετρο και το γυροσκόπιο.

Περιβαλλοντικοί αισθητήρες: Μέτρηση φωτισμού περιβάλλοντος

Ο αισθητήρας φωτός του Android μετράει το φως του περιβάλλοντος σε μονάδες "lux", που είναι η ένταση του φωτός όπως αντιλαμβάνεται το ανθρώπινο μάτι. Η τιμή lux που αναφέρθηκε από έναν αισθητήρα μπορεί να διαφέρει σε όλες τις συσκευές, οπότε αν η εφαρμογή σας απαιτεί σταθερές τιμές, τότε ίσως χρειαστεί να χειριστείτε τα ακατέργαστα δεδομένα πριν τα χρησιμοποιήσετε στην εφαρμογή σας.


Σε αυτή την ενότητα θα δημιουργήσουμε μια εφαρμογή που θα ανακτά την τρέχουσα τιμή lux από τον αισθητήρα φωτός της συσκευής, θα την εμφανίζει σε ένα TextView και στη συνέχεια θα ενημερώνει το TextView καθώς θα είναι διαθέσιμα νέα δεδομένα.Στη συνέχεια, μπορείτε να χρησιμοποιήσετε αυτές τις πληροφορίες σε μια σειρά εφαρμογών, για παράδειγμα μπορείτε να δημιουργήσετε μια εφαρμογή φακό που τραβά πληροφορίες από τον αισθητήρα φωτός και στη συνέχεια ρυθμίζει αυτόματα τη δύναμη της δέσμης βάσει των σημερινών επιπέδων φωτισμού.

Δημιουργήστε ένα νέο έργο Android με τις ρυθμίσεις της επιλογής σας και ας ξεκινήσουμε!

Εμφάνιση των δεδομένων αισθητήρων

Θα προσθέσω ένα TextView που θα εμφανίσει τελικά τα δεδομένα που έχουμε αφαιρέσει από τον αισθητήρα φωτός. Αυτό το TextView θα ενημερώνεται όποτε γίνονται διαθέσιμα νέα δεδομένα, οπότε ο χρήστης έχει πάντα πρόσβαση στις πιο πρόσφατες πληροφορίες.

Ανοίξτε το αρχείο activity_main.xml του έργου σας και προσθέστε τα εξής:

Στη συνέχεια, πρέπει να δημιουργήσουμε τον "string_sensor" πόρο string που αναφέρεται στη διάταξη μας. Ανοίξτε το αρχείο strings.xml του έργου σας και προσθέστε τα εξής:

Αισθητήρας φωτός:% 1 $ .2f

Το "% 1 $ .2f" είναι ένα σύμβολο κράτησης θέσης που καθορίζει τις πληροφορίες που θέλουμε να εμφανίσουμε και πώς πρέπει να μορφοποιηθεί:

  • %1. Μπορείτε να εισαγάγετε πολλά σύμβολα κράτησης θέσης στον ίδιο πόρο στοιχειοσειράς. "% 1" υποδηλώνει ότι χρησιμοποιούμε ένα μόνο σύμβολο κράτησης θέσης.
  • $.2. Αυτό καθορίζει τον τρόπο με τον οποίο η εφαρμογή μας πρέπει να διαμορφώνει κάθε εισερχόμενη τιμή κινητού σημείου. Το "$ .2" υποδηλώνει ότι η τιμή θα πρέπει να στρογγυλοποιείται σε δύο δεκαδικά ψηφία.
  • ΦΑ. Διαμορφώστε την τιμή ως έναν αριθμό κινητής υποδιαστολής.

Ενώ μερικοί αισθητήρες είναι πιο συνηθισμένοι από άλλους, δεν πρέπει ποτέ να υποθέσετε ότι κάθε συσκευή έχει πρόσβαση στο ίδιο υλικό και λογισμικό. Η διαθεσιμότητα του αισθητήρα μπορεί να διαφέρει ακόμη και σε διάφορες εκδόσεις του Android, καθώς ορισμένοι αισθητήρες δεν εισήχθησαν παρά αργότερα αργότερα στην πλατφόρμα Android.

Μπορείτε να ελέγξετε αν υπάρχει ένας συγκεκριμένος αισθητήρας σε μια συσκευή, χρησιμοποιώντας το πλαίσιο αισθητήρα Android. Στη συνέχεια, μπορείτε να απενεργοποιήσετε ή να ενεργοποιήσετε τμήματα της εφαρμογής σας βάσει της διαθεσιμότητας αισθητήρων ή να εμφανίσετε μια εξήγηση ότι ορισμένες από τις λειτουργίες της εφαρμογής σας δεν θα λειτουργήσουν όπως αναμένεται.

Ενώ έχουμε ανοιχτό το αρχείο μας strings.xml, ας δημιουργήσουμε μια σειρά "no_sensor", την οποία θα εμφανίσουμε αν ο αισθητήρας φωτός δεν είναι διαθέσιμος:

Δεν υπάρχει διαθέσιμος αισθητήρας φωτός

Εάν η εφαρμογή σας δεν μπορεί να προσφέρει καλή εμπειρία χρήστη χωρίς να έχει πρόσβαση σε συγκεκριμένο αισθητήρα, τότε πρέπει να προσθέσετε αυτές τις πληροφορίες στο Manifest σας. Για παράδειγμα, αν η εφαρμογή σας απαιτεί πρόσβαση σε έναν αισθητήρα πυξίδας, μπορείτε να χρησιμοποιήσετε τα εξής:

Τώρα, η εφαρμογή σας μπορεί να μεταφορτωθεί μόνο σε συσκευές που διαθέτουν αισθητήρα πυξίδας.

Αν και αυτό μπορεί να περιορίσει το κοινό σας, είναι πολύ λιγότερο επιζήμιο από το να επιτρέπεται σε κάποιον να κάνει λήψη της αίτησής σας όταν είναι εγγυημένη να έχουν μια κακή εμπειρία, λόγω της διαμόρφωσης αισθητήρα της συσκευής τους.

Επικοινωνία με αισθητήρα: SensorManager, SensorEvents και ακροατές

Για να επικοινωνήσετε με τον αισθητήρα φωτός της συσκευής, πρέπει να ολοκληρώσετε τα παρακάτω βήματα:

1. Αποκτήστε μια παρουσία του SensorManager

Το SensorManager παρέχει όλες τις μεθόδους που χρειάζεστε για να έχετε πρόσβαση στην πλήρη σειρά αισθητήρων της συσκευής.

Για να ξεκινήσετε, δημιουργήστε μια μεταβλητή που θα κρατήσει μια παρουσία του SensorManager:

ιδιωτικό SensorManager lightSensorManager;

Στη συνέχεια, πρέπει να αποκτήσετε μια εμφάνιση του SensorManager, καλώντας τη μέθοδο Context.getSystemService και μεταβιβάζοντας στο παράθυρο Context.SENSOR_SERVICE:

φωςSensorManager = (SensorManager) getSystemService (Context.SENSOR_SERVICE);

2. Πάρτε μια αναφορά στο lightTextView

Στη συνέχεια, πρέπει να δημιουργήσουμε μια μεταβλητή ιδιωτικού μέλους που θα κρατά τα αντικείμενα του TextView και να την αναθέσει στο TextView:

ιδιωτικό TextView lightTextView; ... ... ... lightTextView = (TextView) findViewById (R.id.lightTextView);

3. Ελέγξτε εάν υπάρχει ο αισθητήρας στην τρέχουσα συσκευή

Μπορείτε να αποκτήσετε πρόσβαση σε έναν συγκεκριμένο αισθητήρα καλώντας τη μέθοδο getDefaultSensor () και στη συνέχεια να την περάσετε από τον εν λόγω αισθητήρα. Η σταθερά τύπου για τον αισθητήρα φωτός είναι TYPE_LIGHT, οπότε πρέπει να χρησιμοποιήσουμε τα εξής:

lightSensor = lightSensorManager.getDefaultSensor (Sensor.TYPE_LIGHT);

Εάν ο αισθητήρας δεν υπάρχει σε αυτή τη συσκευή, τότε η μέθοδος getDefaultSensor () θα επιστρέψει null και θα εμφανιστεί η συμβολοσειρά "no_sensor":

Σειρά sens_error = getResources (). GetString (R.string.no_sensor); αν (lightSensor == null) {lightTextView.setText (sensor_error); }}

4. Καταγράψτε τους ακροατές του αισθητήρα

Κάθε φορά που ένας αισθητήρας έχει νέα δεδομένα, το Android παράγει ένα αντικείμενο SensorEvent. Αυτό το αντικείμενο SensorEvent περιλαμβάνει τον αισθητήρα που δημιούργησε το συμβάν, μια χρονική σήμανση και τη νέα τιμή δεδομένων.

Αρχικά, θα επικεντρωθούμε στους αισθητήρες φωτός και εγγύτητας, οι οποίοι επιστρέφουν ένα μόνο κομμάτι δεδομένων. Ωστόσο, ορισμένοι αισθητήρες παρέχουν πολυδιάστατες συστοιχίες για κάθε SensorEvent, συμπεριλαμβανομένου του αισθητήρα διανύσματος περιστροφής, τον οποίο θα διερευνήσουμε προς το τέλος αυτού του άρθρου.

Για να διασφαλιστεί ότι η εφαρμογή μας ενημερώνεται σχετικά με αυτά τα αντικείμενα SensorEvent, πρέπει να καταχωρήσουμε έναν ακροατή για το συγκεκριμένο συμβάν αισθητήρα χρησιμοποιώντας το registerNistener () του SensorManager.

Η μέθοδος registerListener () λαμβάνει τα ακόλουθα επιχειρήματα:

  • Μια εφαρμογή ή ένα πλαίσιο δραστηριότητας.
  • Ο τύπος αισθητήρα που θέλετε να παρακολουθήσετε.
  • Ο ρυθμός με τον οποίο ο αισθητήρας πρέπει να στείλει νέα δεδομένα. Ένα υψηλότερο ποσοστό θα παρέχει στην εφαρμογή σας περισσότερα δεδομένα, αλλά θα χρησιμοποιεί επίσης περισσότερους πόρους του συστήματος, ειδικά τη διάρκεια ζωής της μπαταρίας. Για να διατηρήσετε τη μπαταρία της συσκευής, θα πρέπει να ζητήσετε την ελάχιστη ποσότητα δεδομένων που χρειάζεται η εφαρμογή σας. Θα χρησιμοποιήσω το SensorManager.SENSOR_DELAY_NORMAL, το οποίο στέλνει νέα δεδομένα μία φορά κάθε 200.000 μικροδευτερόλεπτα (0,2 δευτερόλεπτα).

Αφού ακούσετε έναν αισθητήρα αποστράγγισης της μπαταρίας της συσκευής, δεν πρέπει ποτέ να εγγράφετε ακροατές στη μέθοδο onCreate () της εφαρμογής, καθώς αυτό θα προκαλέσει τη συνέχιση της αποστολής δεδομένων από τους αισθητήρες ακόμα και όταν η εφαρμογή βρίσκεται στο παρασκήνιο.

Αντ 'αυτού, θα πρέπει να καταχωρήσετε τους αισθητήρες σας στη μέθοδο onStart () της εφαρμογής του κύκλου ζωής:

@Override προστατεύεται void onStart () {super.onStart (); // Αν ο αισθητήρας είναι διαθέσιμος στην τρέχουσα συσκευή ... // αν (lightSensor! = Null) {//....εκκινήστε την ακρόαση // lightSensorManager.registerListener (αυτό, lightSensor, SensorManager.SENSOR_DELAY_NORMAL); }}

5. Εφαρμόστε τις επανάκλησεις του SensorEventListener

Το SensorEventListener είναι μια διεπαφή που λαμβάνει ειδοποιήσεις από το SensorManager
όποτε υπάρχουν νέα δεδομένα ή αλλάζει η ακρίβεια του αισθητήρα.

Το πρώτο βήμα είναι η τροποποίηση της υπογραφής της κλάσης μας για την υλοποίηση της διεπαφής SensorEventListener:

δημόσια class MainActivity εκτείνεται AppCompatActivity υλοποιεί SensorEventListener {

Στη συνέχεια, πρέπει να εφαρμόσουμε τις ακόλουθες μεθόδους επανάκλησης:

onSensorChanged ()

Αυτή η μέθοδος καλείται σε απάντηση σε κάθε νέο SensorEvent.

Τα δεδομένα των αισθητήρων μπορούν συχνά να αλλάξουν γρήγορα, οπότε η εφαρμογή σας ενδέχεται να καλεί τη μέθοδο onSensorChanged () σε τακτική βάση. Για να διατηρήσετε την εφαρμογή σας ομαλά, θα πρέπει να εκτελέσετε όσο το δυνατόν λιγότερη εργασία μέσα στη μέθοδο onSensorChanged ().

@Override δημόσιο κενό onSensorChanged (SensorEvent αισθητήραEvent) {// Να κάνει //}

onAccuracyChanged ()

Αν η ακρίβεια του αισθητήρα βελτιωθεί ή απορριφθεί, τότε το Android θα καλέσει τη μέθοδο onAccuracyChanged () και θα του περάσει ένα αντικείμενο αισθητήρα που περιέχει τη νέα τιμή ακρίβειας, όπως SENSOR_STATUS_UNRELIABLE ή SENSOR_STATUS_ACCURACY_HIGH.

Ο αισθητήρας φωτός δεν αναφέρει αλλαγές ακρίβειας, επομένως θα αφήσω κενή την επιστροφή κλήσης onAccuracyChanged ():

@Override δημόσιο κενό onAccuracyChanged (Αισθητήρας αισθητήρα, int i) {// Να κάνει //}}

6. Ανακτήσετε την τιμή του αισθητήρα

Κάθε φορά που έχουμε μια νέα τιμή, πρέπει να καλέσουμε τη μέθοδο onSensorChanged () και να ανακτήσουμε τη συμβολοσειρά "light_sensor". Στη συνέχεια, μπορούμε να παρακάμψουμε το κείμενο κειμένου σύμβολο σύμβολο (% 1 $ .2f) και να εμφανιστεί η ενημερωμένη συμβολοσειρά ως τμήμα του TextView:

@Override public void onSensorChanged (SensorEvent sensorEvent) {// Η τρέχουσα τιμή του αισθητήρα // float currentValue = αισθητήραςEvent.values; // Ανάκτηση της συμβολοσειράς "light_sensor", εισαγωγή της νέας τιμής και εμφάνιση της στο // lightTextView.setText (getResources (). GetString (R.string.light_sensor, currentValue)). }}

7. Καταργήστε την εγγραφή των ακροατών σας

Οι αισθητήρες μπορούν να παράγουν μεγάλα ποσά δεδομένων σε μικρό χρονικό διάστημα, οπότε για να διατηρήσετε τους πόρους της συσκευής θα πρέπει να καταργήσετε την εγγραφή των ακροατών σας όταν δεν χρειάζονται πλέον.

Για να σταματήσετε να ακούτε συμβάντα αισθητήρων όταν η εφαρμογή βρίσκεται στο παρασκήνιο, προσθέστε unregisterListener () στη μέθοδο του κύκλου ζωής onStop () του έργου:

@Override προστατεύεται void onStop () {super.onStop (); lightSensorManager.unregisterListener (αυτό); }}

Σημειώστε ότι δεν πρέπει να καταργήσετε την εγγραφή των ακροατών σας στο onPause (), όπως στο Android 7.0 και σε υψηλότερες εφαρμογές μπορούν να εκτελούνται σε λειτουργία split-screen και picture-in-picture, όπου βρίσκονται σε κατάσταση παύσης, αλλά παραμένουν ορατές στην οθόνη.

Χρησιμοποιώντας τους αισθητήρες φωτός του Android: Ολοκληρώθηκε ο κωδικός

Αφού ολοκληρώσετε όλα τα παραπάνω βήματα, το MainActivity του έργου σας θα πρέπει να φαίνεται ως εξής:

εισαγωγή καιroid.support.v7.app.AppCompatActivity; εισαγωγή android.os.Bundle; εισαγωγή καιroid.content.Context. εισαγωγή καιroid.hardware.Sensor; εισαγωγή καιroid.hardware.SensorEvent; εισαγωγή καιroid.hardware.SensorEventListener; εισαγωγή καιroid.hardware.SensorManager; εισαγωγή καιroid.widget.TextView; η δημόσια κλάση MainActivity επεκτείνει την AppCompatActivity // Εφαρμογή της διεπαφής SensorEventListener // υλοποιεί το SensorEventListener {// Δημιουργήστε τις μεταβλητές σας // private Sensor lightSensor; ιδιωτικό SensorManager lightSensorManager; ιδιωτικό TextView lightTextView; @Override προστατεύεται void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); lightTextView = (TextView) findViewById (R.id.lightTextView); // Πάρτε μια εμφάνιση του SensorManager // lightSensorManager = (SensorManager) getSystemService (Context.SENSOR_SERVICE); // Ελέγξτε για αισθητήρα φωτός // lightSensor = lightSensorManager.getDefaultSensor (Sensor.TYPE_LIGHT); // Αν ο αισθητήρας φωτός δεν υπάρχει, τότε εμφανίζεται ένα σφάλμα // String sensor_error = getResources (). GetString (R.string.no_sensor); αν (lightSensor == null) {lightTextView.setText (sensor_error); }} @Περιορισμένη προστασία void onStart () {super.onStart (); // Αν ο αισθητήρας είναι διαθέσιμος στην τρέχουσα συσκευή ... // αν (lightSensor! = Null) {//....καταχωρίστε έναν ακροατή // lightSensorManager.registerListener (αυτό, lightSensor, // Καθορίστε πόσο συχνά θέλετε να λήψη νέων δεδομένων // SensorManager.SENSOR_DELAY_NORMAL); }} @Override προστατεύεται void onStop () {super.onStop (); // Διαγραφή του ακροατή σας // lightSensorManager.unregisterListener (αυτό); } @Override public void onSensorChanged (SensorEvent sensorEvent) {// Η τρέχουσα τιμή του αισθητήρα // float currentValue = αισθητήραςEvent.values; // Ανάκτηση της συμβολοσειράς light_sensor, εισαγωγή της νέας τιμής και ενημέρωση του TextView // lightTextView.setText (getResources (). GetString (R.string.light_sensor, currentValue)). } @Override // Εάν η ακρίβεια του αισθητήρα αλλάξει ... .// δημόσιο κενό onAccuracyChanged (αισθητήρας αισθητήρα, int i) {// TO DO //}}

Δοκιμάστε την ολοκληρωμένη εφαρμογή αισθητήρα Android

Για να δοκιμάσετε αυτήν την εφαρμογή σε ένα φυσικό Android smartphone ή tablet:

  • Εγκαταστήστε το έργο στη συσκευή σας (επιλέγοντας "Εκτέλεση> Εκτέλεση" από τη γραμμή εργαλείων του Android Studio).
  • Αν και ποικίλλει μεταξύ των συσκευών, ο αισθητήρας φωτός βρίσκεται συχνά στην επάνω δεξιά γωνία της οθόνης. Για να χειριστείτε τα επίπεδα φωτισμού, μετακινήστε τη συσκευή σας πιο κοντά και στη συνέχεια μακριά από μια πηγή φωτός. Εναλλακτικά, μπορείτε να δοκιμάσετε να καλύψετε τη συσκευή με το χέρι σας, για να αποκλείσετε το φως. Η τιμή "Αισθητήρας φωτός" θα πρέπει να αυξηθεί και να μειωθεί, ανάλογα με την ποσότητα φωτός που διατίθεται.

Εάν χρησιμοποιείτε μια εικονική συσκευή Android (AVD), τότε ο εξομοιωτής διαθέτει ένα σύνολο εικονικών ελέγχων αισθητήρα που μπορείτε να χρησιμοποιήσετε για την προσομοίωση διαφόρων συμβάντων αισθητήρων. Μπορείτε να αποκτήσετε πρόσβαση σε αυτά τα εικονικά στοιχεία ελέγχου αισθητήρα, μέσω του παραθύρου "Εκτεταμένες λειτουργίες" του προσομοιωτή:

  • Εγκαταστήστε την εφαρμογή στο AVD σας.
  • Παράλληλα με το AVD, θα δείτε μια λωρίδα κουμπιών. Εντοπίστε το κουμπί "Περισσότερα" (όπου βρίσκεται ο δρομέας στο επόμενο στιγμιότυπο) και κάντε κλικ σε αυτό. Αυτό εκκινεί το παράθυρο "Εκτεταμένα στοιχεία ελέγχου".

  • Στο αριστερό μενού, επιλέξτε "Εικονικοί αισθητήρες".
  • Επιλέξτε την καρτέλα "Πρόσθετοι αισθητήρες". Αυτή η καρτέλα περιέχει διάφορα ρυθμιστικά που μπορείτε να χρησιμοποιήσετε για να προσομοιώσετε διαφορετικά γεγονότα αισθητήρων θέσης και περιβάλλοντος.

  • Εντοπίστε το ρυθμιστικό "Φωτισμός (λουξ)" και σύρετέ το αριστερά και δεξιά, για να αλλάξετε τα προσομοιωμένα επίπεδα φωτισμού. Η εφαρμογή σας θα πρέπει να εμφανίζει αυτές τις μεταβαλλόμενες τιμές, σε πραγματικό χρόνο.

Μπορείτε να κατεβάσετε το ολοκληρωμένο έργο από το GitHub.

Μετρήστε την απόσταση, με τους αισθητήρες εγγύτητας του Android

Τώρα έχουμε δει πώς να ανακτήσουμε πληροφορίες από έναν περιβαλλοντικό αισθητήρα, ας δούμε πώς θα εφαρμόζατε αυτή τη γνώση σε ένα θέση αισθητήρα.

Σε αυτήν την ενότητα, θα χρησιμοποιήσουμε τον αισθητήρα εγγύτητας της συσκευής για να παρακολουθήσετε την απόσταση μεταξύ του smartphone ή του tablet σας και άλλων αντικειμένων. Εάν η εφαρμογή σας έχει οποιαδήποτε λειτουργία φωνής, τότε ο αισθητήρας εγγύτητας μπορεί να σας βοηθήσει να προσδιορίσετε πότε το smartphone κρατιέται στο αυτί του χρήστη, για παράδειγμα, όταν πρόκειται για τηλεφωνική συνομιλία. Στη συνέχεια, μπορείτε να χρησιμοποιήσετε αυτές τις πληροφορίες για να απενεργοποιήσετε τα συμβάντα αφής, οπότε ο χρήστης δεν θα κλείσει κατά λάθος ή θα ενεργοποιήσει άλλα ανεπιθύμητα συμβάντα στα μέσα της συνομιλίας.

Δημιουργία διεπαφής χρήστη

Θα προβάλλω τα δεδομένα εγγύτητας στην οθόνη, ώστε να μπορείτε να παρακολουθήσετε την ενημέρωση σε πραγματικό χρόνο. Για να βοηθήσουμε να διατηρήσουμε τα πράγματα απλά, ας επαναχρησιμοποιήσουμε ένα μεγάλο μέρος της διάταξης από την προηγούμενη εφαρμογή μας:

Στη συνέχεια, ανοίξτε το αρχείο strings.xml και δημιουργήστε μια συμβολοσειρά "proximity_sensor". Για άλλη μια φορά, αυτή η συμβολοσειρά πρέπει να περιέχει ένα σύμβολο κράτησης θέσης, το οποίο τελικά θα συμπληρωθεί με δεδομένα που προέρχονται από τον αισθητήρα εγγύτητας:

Αισθητήρας εγγύτητας Αισθητήρας εγγύτητας:% 1 $ .2f Δεν υπάρχει διαθέσιμος αισθητήρας εγγύτητας

Λήψη δεδομένων από τον αισθητήρα εγγύτητας

Παρόμοια με τον αισθητήρα φωτός, ο αισθητήρας εγγύτητας του Android επιστρέφει μια μοναδική τιμή δεδομένων, πράγμα που σημαίνει ότι μπορούμε να επαναχρησιμοποιήσουμε μεγάλο μέρος του κώδικα από την προηγούμενη εφαρμογή μας. Ωστόσο, υπάρχουν μερικές σημαντικές διαφορές, καθώς και ορισμένες αλλαγές που σχετίζονται με το όνομα, οι οποίες καθιστούν ευκολότερη την παρακολούθηση αυτού του κώδικα:

  • Δημιουργήστε ένα στιγμιότυπο του SensorManager, το οποίο αυτή τη φορά πρόκειται να ονομάσω "proximitySensorManager".
  • Αποκτήστε μια εμφάνιση του "proximitySensorManager".
  • Δημιουργήστε μια αναφορά στο "proximityTextView".
  • Καλέστε τη μέθοδο getDefaultSensor () και περάστε τον αισθητήρα TYPE_PROXIMITY.
  • Εγγραφείτε και καταργήστε την εγγραφή ακροατών για τον αισθητήρα εγγύτητας.

Αφού κάνετε αυτές τις τροποποιήσεις, θα πρέπει να καταλήξετε στα εξής:

εισαγωγή καιroid.support.v7.app.AppCompatActivity; εισαγωγή android.os.Bundle; εισαγωγή καιroid.content.Context. εισαγωγή καιroid.hardware.Sensor; εισαγωγή καιroid.hardware.SensorEvent; εισαγωγή καιroid.hardware.SensorManager; εισαγωγή καιroid.hardware.SensorEventListener; εισαγωγή καιroid.widget.TextView; δημόσια class MainActivity επεκτείνει AppCompatActivity // Εφαρμογή της διεπαφής SensorEventListener // υλοποιεί SensorEventListener {// Δημιουργήστε τις μεταβλητές σας // ιδιωτική Sensor proximitySensor; ιδιωτική SensorManager proximitySensorManager; ιδιωτικό TextView proximityTextView; @Override προστατεύεται void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); proximityTextView = (TextView) findViewById (R.id.proximityTextView); // Πάρτε μια εμφάνιση του SensorManager // proximitySensorManager = (SensorManager) getSystemService (Context.SENSOR_SERVICE); // Ελέγξτε για έναν αισθητήρα εγγύτητας // proximitySensor = proximitySensorManager.getDefaultSensor (Sensor.TYPE_PROXIMITY); // Αν ο αισθητήρας εγγύτητας δεν υπάρχει, τότε εμφανίζεται ένα σφάλμα // String sensor_error = getResources (). GetString (R.string.no_sensor); αν (proximitySensor == null) {proximityTextView.setText (sensor_error); }} @Περιορισμένη προστασία void onStart () {super.onStart (); // Αν ο αισθητήρας είναι διαθέσιμος στην τρέχουσα συσκευή ... // if (proximitySensor! = Null) {//....η εγγραφή ενός ακροατή // proximitySensorManager.registerListener (αυτό, proximitySensor, // Καθορίστε πόσο συχνά θέλετε να λήψη νέων δεδομένων // SensorManager.SENSOR_DELAY_NORMAL); }} @Override προστατεύεται void onStop () {super.onStop (); // Καταργήστε την εγγραφή του ακροατή σας για να διατηρήσετε τους πόρους του συστήματος // proximitySensorManager.unregisterListener (αυτό); } @Override public void onSensorChanged (SensorEvent sensorEvent) {// Η τρέχουσα τιμή του αισθητήρα // float currentValue = αισθητήραςEvent.values; // Ανάκτηση της συμβολοσειράς "proximity_sensor", εισαγωγή της νέας τιμής και ενημέρωση του TextView // proximityTextView.setText (getResources (). GetString (R.string.proximity_sensor, currentValue)). } @Override // Αν αλλάξει η ακρίβεια του αισθητήρα ... .// δημόσιο κενό onAccuracyChanged (Αισθητήρας αισθητήρα, int i) {//...TO DO //}}

Δοκιμή: Πόσο κοντά είναι ο χρήστης στη συσκευή του;

Για να θέσετε αυτήν την εφαρμογή σε δοκιμή σε ένα φυσικό Android smartphone ή tablet, εγκαταστήστε την εφαρμογή στη συσκευή σας και, στη συνέχεια, πειραματιστείτε, μετακινώντας το χέρι σας προς την οθόνη και, στη συνέχεια, την απομακρύνοντας ξανά. Η τιμή "Αισθητήρας εγγύτητας" πρέπει να καταγράφει τις κινήσεις σας.

Απλώς γνωρίζετε ότι οι αισθητήρες προσέγγισης μπορεί να διαφέρουν μεταξύ των συσκευών. Ορισμένες συσκευές ενδέχεται να εμφανίζουν μόνο δύο τιμές εγγύτητας - μία για να υποδεικνύει "Κοντά" και μία για να υποδεικνύει "Far" - γι 'αυτό μην εκπλαγείτε αν δεν βλέπετε μεγάλη ποικιλία στη φυσική σας συσκευή Android.

Για να δοκιμάσετε αυτήν την εφαρμογή σε έναν εξομοιωτή:

  • Εγκαταστήστε την εφαρμογή σας σε ένα AVD.
  • Εντοπίστε το κουμπί "Περισσότερα" με τρεις κουκίδες και δώστε το κλικ, το οποίο εκκινεί το παράθυρο "Εκτεταμένες ρυθμίσεις".
  • Στο αριστερό μενού του παραθύρου, επιλέξτε "Εικονικοί αισθητήρες".
  • Επιλέξτε την καρτέλα "Πρόσθετοι αισθητήρες".
  • Βρείτε το ρυθμιστικό "Απόσταση" και σύρετέ το αριστερά και δεξιά για να μιμηθεί ένα αντικείμενο που βρίσκεται πιο κοντά στη συσκευή και στη συνέχεια πιο μακριά. Οι τιμές "αισθητήρα προσέγγισης" πρέπει να αλλάξουν, καθώς χειρίζεστε το ρυθμιστικό.

Μπορείτε να κατεβάσετε το ολοκληρωμένο έργο από το GitHub.

Αισθητήρες κίνησης: Επεξεργασία πολυδιάστατων συστοιχιών

Μέχρι αυτό το σημείο, εστιάσαμε σε αισθητήρες που παρέχουν ένα μόνο στοιχείο δεδομένων, αλλά υπάρχουν ορισμένοι αισθητήρες που παρέχουν πολυδιάστατες συστοιχίες για κάθε SensorEvent. Αυτοί οι πολυδιάστατοι αισθητήρες περιλαμβάνουν αισθητήρες κίνησης, στους οποίους θα επικεντρωθούμε σε αυτό το τελευταίο τμήμα.

Οι αισθητήρες κίνησης μπορούν να σας βοηθήσουν:

  • Παρέχετε μια εναλλακτική μέθοδο εισαγωγής χρηστών. Για παράδειγμα, εάν αναπτύσσετε ένα κινητό παιχνίδι, τότε ο χρήστης μπορεί να μετακινήσει τον χαρακτήρα του γύρω από την οθόνη, ανακλώνοντας τη συσκευή του.
  • Δραστηριότητα χρήστη Infer. Αν έχετε δημιουργήσει μια εφαρμογή παρακολούθησης δραστηριότητας, τότε οι αισθητήρες κίνησης μπορούν να σας βοηθήσουν να μετρήσετε εάν ο χρήστης ταξιδεύει με αυτοκίνητο, τρέχει ή κάθονται στο γραφείο του.
  • Προσδιορίστε με ακρίβεια τον προσανατολισμόΕίναι δυνατή η εξαγωγή συντεταγμένων από αισθητήρες κίνησης μιας συσκευής και στη συνέχεια η μετάφρασή τους με βάση το σύστημα συντεταγμένων της Γης, για να αποκτήσετε την ακριβέστερη εικόνα του τρέχοντος προσανατολισμού της συσκευής.

Σε αυτήν την τελική ενότητα, θα χρησιμοποιήσουμε τον αισθητήρα διανύσματος περιστροφής (TYPE_ROTATION_VECTOR). Σε αντίθεση με τους αισθητήρες φωτός και εγγύτητας, αυτός είναι ένας αισθητήρας λογισμικού που συνδυάζει δεδομένα από τους αισθητήρες επιταχυνσιόμετρο, μαγνητόμετρο και γυροσκόπιο της συσκευής. Παρόλο που η εργασία με αυτόν τον αισθητήρα απαιτεί συχνά να πραγματοποιείτε μαθηματικές μετατροπές και μετασχηματισμούς, μπορεί επίσης να σας παρέχει μια σειρά από εξαιρετικά ακριβείς πληροφορίες σχετικά με τη συσκευή.

Δημιουργούμε μια εφαρμογή που χρησιμοποιεί τον αισθητήρα διάνυσμα περιστροφής για να μετρήσει:

  • Πίσσα. Αυτή είναι η κλίση από πάνω προς τα κάτω της συσκευής.
  • Ρολό. Αυτή είναι η κλίση από αριστερά προς τα δεξιά της συσκευής.

Εμφάνιση δεδομένων ανάλυσης και ανάλυσης σε πραγματικό χρόνο

Εφόσον μετράμε δύο μετρήσεις, πρέπει να δημιουργήσουμε δύο TextViews και δύο αντίστοιχους πόρους συμβολοσειράς:

Ανοίξτε το αρχείο strings.xml και προσθέστε τα εξής:

MotionSensors Αισθητήρας Pitch:% 1 $ .2f Αισθητήρας ρολού:% 1 $ .2f Δεν υπάρχει διαθέσιμος αισθητήρας κίνησης

Χρησιμοποιώντας τον αισθητήρα φορέα περιστροφής στην εφαρμογή σας

Θα επαναχρησιμοποιούμε μέρος του κώδικα από τις προηγούμενες εφαρμογές μας, οπότε ας επικεντρωθούμε στις περιοχές όπου η επικοινωνία με τον αισθητήρα φορέα περιστροφής είναι σημαντικά διαφορετική από αυτή που έχουμε δει πριν.

1. Χρησιμοποιήστε το TYPE_ROTATION_VECTOR

Εφόσον δουλεύουμε με τον αισθητήρα διάνυσμα περιστροφής, πρέπει να καλέσουμε τη μέθοδο getDefaultSensor () και στη συνέχεια να την περάσουμε με τη σταθερά TYPE_ROTATION_VECTOR:

positionSensorManager.getDefaultSensor (Sensor.TYPE_ROTATION_VECTOR).

2. Μεταφράστε τα δεδομένα του αισθητήρα

Σε αντίθεση με τους προηγούμενους αισθητήρες φωτός και εγγύτητας, οι αισθητήρες κίνησης επιστρέφουν πολυδιάστατες συστοιχίες τιμών αισθητήρων για κάθε SensorEvent. Αυτές οι τιμές μορφοποιούνται χρησιμοποιώντας το τυπικό σύστημα συντεταγμένων "X, Y, Z", το οποίο υπολογίζεται σε σχέση με τη συσκευή όταν κρατιέται στον προεπιλεγμένο "φυσικό" προσανατολισμό.

Το Android δεν αλλάζει τις συντεταγμένες X, Y και Z γύρω για να ταιριάζει με τον τρέχοντα προσανατολισμό της συσκευής, οπότε ο άξονας "X" θα παραμείνει ο ίδιος ανεξάρτητα από το αν η συσκευή βρίσκεται σε κατακόρυφη ή οριζόντια θέση. Όταν χρησιμοποιείτε τον αισθητήρα διανύσματος περιστροφής, ίσως χρειαστεί να μετατρέψετε τα εισερχόμενα δεδομένα ώστε να ταιριάζουν με την τρέχουσα περιστροφή της συσκευής.

Το πορτρέτο είναι ο προεπιλεγμένος προσανατολισμός για τα περισσότερα smartphones, αλλά δεν πρέπει να υποθέσετε ότι αυτό θα συμβεί όλα Συσκευές Android, ιδιαίτερα δισκία. Σε αυτό το άρθρο, θα χρησιμοποιήσουμε ένα περιστρεφόμενο πλέγμα για να μεταφράσουμε τα δεδομένα του αισθητήρα από το πρωτότυπο, συσκευή σύστημα συντεταγμένων, στο Γη σύστημα συντεταγμένων, που αντιπροσωπεύει την κίνηση και τη θέση της συσκευής σε σχέση με τη Γη. Αν χρειαστεί, μπορούμε να επανατοποθετήσουμε τα δεδομένα αισθητήρα, βάσει του τρέχοντος προσανατολισμού της συσκευής.

Πρώτον, το σύστημα συντεταγμένων της συσκευής είναι ένα τυπικό σύστημα συντεταγμένων X, Y, Z, όπου κάθε σημείο σε κάθε έναν από τους τρεις άξονες αντιπροσωπεύεται από έναν διανυσματικό 3D. Αυτό σημαίνει ότι πρέπει να δημιουργήσουμε μια σειρά από 9 τιμές float:

float rotationMatrix = νέο float;

Στη συνέχεια, μπορούμε να περάσουμε αυτόν τον πίνακα στη μέθοδο getRotationMatrix ():

SensorManager.getRotationMatrixFromVector (rotationMatrix, φορείς). int worldAxisX = SensorManager.AXIS_X; int worldAxisZ = SensorManager.AXIS_Z;

Το επόμενο βήμα είναι η χρήση της μεθόδου SensorManager.remapCoordinateSystem () για τη μετατόπιση των δεδομένων αισθητήρα, με βάση τον τρέχοντα προσανατολισμό της συσκευής.

Η μέθοδος SensorManager.remapCoordinateSystem () λαμβάνει τα ακόλουθα επιχειρήματα:

  • Ο αρχικός πίνακας περιστροφής.
  • Οι άξονες που θέλετε να αντικαταστήσετε.
  • Η συστοιχία που χρησιμοποιείτε με αυτά τα νέα δεδομένα.

Εδώ είναι ο κώδικας που θα χρησιμοποιήσω στην εφαρμογή μου:

ρυθμιζόμενο με floatRotationMatrix = νέος πλωτήρας; Σύστημα SensorManager.remapCoordinateSystem (rotationMatrix, worldAxisX, worldAxisZ, προσαρμοσμένοRotationMatrix);

Τέλος, θα καλέσουμε το SensorManager.getOrientation και θα του πούμε να χρησιμοποιήσει το adjustedRotationMatrix:

SensorManager.getOrientation (προσαρμοσμένοRotationMatrix, προσανατολισμός);

3. Ενημερώστε τις συμβολοσειρές κράτησης θέσης

Δεδομένου ότι έχουμε δύο σύνολα δεδομένων (pitch και roll), πρέπει να ανακτήσουμε δύο ξεχωριστές συμβολοσειρές σύμβολο κράτησης θέσης, να τις συμπληρώσουμε με τις σωστές τιμές και στη συνέχεια να ενημερώσουμε την αντίστοιχη TextView:

pitchTextView.setText (getResources (). getString (R.string.pitch_sensor, pitch)). rollTextView.setText (getResources (). getString (R.string.roll_sensor, roll)).

Εμφάνιση πολλαπλών δεδομένων αισθητήρων: Ολοκληρωμένος κωδικός

Αφού εκτελέσετε τα παραπάνω βήματα, το MainActivity σας θα πρέπει να φαίνεται ως εξής:

εισαγωγή καιroid.app.Activity; εισαγωγή android.os.Bundle; εισαγωγή καιroid.hardware.Sensor; εισαγωγή καιroid.hardware.SensorEvent; εισαγωγή καιroid.hardware.SensorEventListener; εισαγωγή καιroid.hardware.SensorManager; εισαγωγή καιroid.widget.TextView; δημόσια τάξη MainActivity εκτείνεται Δραστηριότητα υλοποιεί SensorEventListener {ιδιωτικό SensorManager motionSensorManager; ιδιωτικός αισθητήρας κίνησης αισθητήρα; ιδιωτική TextView pitchTextView; ιδιωτικό TextView rollTextView; ιδιωτική στατική τελική int SENSOR_DELAY = 500 * 1000; ιδιωτική στατική τελική int FROM_RADS_TO_DEGS = -57; @Override προστατεύεται void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); pitchTextView = (TextView) findViewById (R.id.pitchTextView); rollTextView = (TextView) findViewById (R.id.rollTextView); δοκιμάστε {motionSensorManager = (SensorManager) getSystemService (Δραστηριότητα.SENSOR_SERVICE); motionSensor = motionSensorManager.getDefaultSensor (Sensor.TYPE_ROTATION_VECTOR); motionSensorManager.registerListener (αυτό, motionSensor, SENSOR_DELAY); } αλίευση (Εξαίρεση e) {pitchTextView.setText (R.string.no_sensor); rollTextView.setText (R.string.no_sensor); }} @Override public void onAccuracyChanged (Αισθητήρας αισθητήρα, ακρίβεια int) {// Να κάνει //} @Override public void onSensorChanged (συμβάν SensorEvent) {if (event.sensor == motionSensor) {update (event.values); }} ιδιωτική ανανέωση κενών (διανύσματα float) {// Υπολογισμός μήτρας περιστροφής // float rotationMatrix = new float; SensorManager.getRotationMatrixFromVector (rotationMatrix, φορείς). int worldAxisX = SensorManager.AXIS_X; int worldAxisZ = SensorManager.AXIS_Z; // Επανατοποθετήστε το πλέγμα με βάση τον τρέχοντα προσανατολισμό της δραστηριότητας // ρυθμιζόμενο με floatRotationMatrix = νέο float; Σύστημα SensorManager.remapCoordinateSystem (rotationMatrix, worldAxisX, worldAxisZ, προσαρμοσμένοRotationMatrix); // Υπολογισμός του προσανατολισμού των συσκευών // προσανατολισμός πλωτήρα = νέος πλωτήρας; // Προσθέστε τη σειρά των τιμών float στη μέθοδο getOrientation () // SensorManager.getOrientation (προσαρμοσμένηRotationMatrix, προσανατολισμός); float pitch = προσανατολισμός * FROM_RADS_TO_DEGS; float roll = προσανατολισμός * FROM_RADS_TO_DEGS; // Ενημέρωση των TextViews με τις τιμές pitch και roll // pitchTextView.setText (getResources (). GetString (R.string.pitch_sensor, pitch)); rollTextView.setText (getResources (). getString (R.string.roll_sensor, roll)). }}

Μπορείτε να κατεβάσετε το ολοκληρωμένο έργο από το GitHub.

Δοκιμάζοντας την τελική εφαρμογή αισθητήρα Android

Για να δοκιμάσετε αυτή την εφαρμογή εναλλαγής φορέα Android σε ένα φυσικό Android smartphone ή tablet:

  • Εγκαταστήστε την εφαρμογή στη συσκευή σας.
  • Τοποθετήστε το smartphone ή το tablet σας σε επίπεδη επιφάνεια. Σημειώστε ότι οι αισθητήρες κίνησης είναι εξαιρετικά ευαίσθητοι, οπότε δεν είναι ασυνήθιστο για μια φαινομενικά ακίνητη συσκευή να αναφέρει τις διακυμάνσεις των τιμών ανύψωσης και ροής.
  • Για να δοκιμάσετε το βήμα, σηκώστε το κάτω μέρος της συσκευής σας έτσι ώστε να κλίνει μακριά από σας. Η τιμή του βήματος πρέπει να αλλάξει δραματικά.
  • Για να δοκιμάσετε το ρολό, προσπαθήστε να σηκώσετε την αριστερή πλευρά της συσκευής σας, οπότε γυρνάτε προς τα αριστερά - παρακολουθήστε την τιμή του κυλίνδρου!

Εάν δοκιμάζετε το έργο σας σε έναν εξομοιωτή:

  • Εγκαταστήστε την εφαρμογή στο AVD σας.
  • Επιλέξτε "Περισσότερα", το οποίο εκκινεί το παράθυρο "Εκτεταμένες ρυθμίσεις".
  • Στο αριστερό μενού, επιλέξτε "Εικονικοί αισθητήρες".
  • Βεβαιωθείτε ότι έχετε επιλέξει την καρτέλα "Επιταχυνσιόμετρο". Αυτή η καρτέλα περιέχει στοιχεία ελέγχου που μπορούν να προσομοιώσουν αλλαγές στη θέση και τον προσανατολισμό της συσκευής.
  • Δοκιμάστε να δοκιμάσετε τους διάφορους συρόμενους (Περιστροφή: Z-Rot, X-Rot, Y-Rot και Μετακίνηση: X, Y και Z) και τα διάφορα κουμπιά "Περιστροφή συσκευής" "Και" Sensor Pitch ".

Τυλίγοντας

Σε αυτό το άρθρο, είδαμε πώς μπορείτε να ανακτήσετε δεδομένα από τις τρεις κύριες κατηγορίες αισθητήρων Android: περιβάλλον, θέση και κίνηση και πώς να παρακολουθείτε αυτά τα δεδομένα σε πραγματικό χρόνο.

Έχετε δει εφαρμογές Android που χρησιμοποιούν αισθητήρες με ενδιαφέροντα ή μοναδικά μέσα; Ενημερώστε μας στα σχόλια παρακάτω!

Η amung αποκτά την Joyent, μια αμερικανική εταιρεία που παρέχει υπηρεσίες cloud και υποδομή.Η Joyent, που ιδρύθηκε το 2004 και εδρεύει στο Σαν Φρανσίσκο, είναι γνωστή για τα προϊόντα Platform-a-a-ervi...

Ενώ οι amung και η LG πραγματοποιούν και οι δύο σημαντικές ανακοινώσεις προϊόντων στο Λας Βέγκας κατά τη διάρκεια του CE 2019, και οι δύο εταιρείες κυκλοφόρησαν κάποιες κακές οικονομικές ειδήσεις. Η a...

Δημοφιλή Στην Περιοχή