You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AreaFragment.java 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. package com.example.meinwald.ui.area;
  2. import android.Manifest;
  3. import android.annotation.SuppressLint;
  4. import android.app.AlertDialog;
  5. import android.content.DialogInterface;
  6. import android.content.pm.PackageManager;
  7. import android.database.DataSetObserver;
  8. import android.location.Location;
  9. import android.os.Bundle;
  10. import android.os.PowerManager;
  11. import android.preference.PreferenceManager;
  12. import android.util.Log;
  13. import android.view.Gravity;
  14. import android.view.LayoutInflater;
  15. import android.view.View;
  16. import android.view.ViewGroup;
  17. import android.widget.AdapterView;
  18. import android.widget.Button;
  19. import android.widget.ListView;
  20. import android.widget.TextView;
  21. import android.widget.Toast;
  22. import androidx.annotation.NonNull;
  23. import androidx.core.app.ActivityCompat;
  24. import androidx.core.content.ContextCompat;
  25. import androidx.fragment.app.Fragment;
  26. import com.example.meinwald.BuildConfig;
  27. import com.example.meinwald.R;
  28. import com.google.android.gms.location.FusedLocationProviderClient;
  29. import com.google.android.gms.location.LocationServices;
  30. import com.google.android.gms.maps.CameraUpdateFactory;
  31. import com.google.android.gms.maps.model.LatLng;
  32. import com.google.android.gms.tasks.OnCompleteListener;
  33. import com.google.android.gms.tasks.Task;
  34. import com.google.android.material.floatingactionbutton.FloatingActionButton;
  35. import org.json.JSONArray;
  36. import org.json.JSONException;
  37. import org.json.JSONObject;
  38. import java.io.BufferedReader;
  39. import java.io.File;
  40. import java.io.FileNotFoundException;
  41. import java.io.FileOutputStream;
  42. import java.io.FileReader;
  43. import java.io.IOException;
  44. import java.io.PrintWriter;
  45. import java.util.ArrayList;
  46. import java.util.List;
  47. import static android.content.Context.POWER_SERVICE;
  48. public class AreaFragment extends Fragment {
  49. private static final String TAG = AreaFragment.class.getSimpleName();
  50. /**
  51. * ______________________________________________________________________________________________
  52. * AREA
  53. */
  54. private OwnArea newArea = new OwnArea();
  55. private List<OwnArea> allAreas;
  56. private ListView areaList;
  57. private static final String KEY_AREA_REFERENCES = "areaReferences";
  58. private List<AreaReference> areaReferences;
  59. /**
  60. * ______________________________________________________________________________________________
  61. * LOCATION
  62. */
  63. private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
  64. /**
  65. * The geographical location where the device is currently located.
  66. * That is the last-known location retrieved by the Fused Location Provider.
  67. */
  68. private Location mLastKnownLocation;
  69. /**
  70. * The entry point to the Fused Location Provider.
  71. */
  72. private FusedLocationProviderClient mFusedLocationProviderClient;
  73. private boolean mLocationPermissionGranted;
  74. /**
  75. * The geographical locations which were received from location tracking.
  76. */
  77. private List<LatLng> newPositions;
  78. /**
  79. * ______________________________________________________________________________________________
  80. * CAMERA
  81. */
  82. private static final int MY_CAMERA_PERMISSION_CODE = 100;
  83. private boolean mCameraPermissionGranted;
  84. private static final int CAMERA_REQUEST = 1888;
  85. /**
  86. * ______________________________________________________________________________________________
  87. * STORAGE
  88. */
  89. private static final int READ_EXTERNAL_STORAGE_CODE = 200;
  90. private static final int WRITE_EXTERNAL_STORAGE_CODE = 201;
  91. private boolean mReadStorageGranted;
  92. private boolean mWriteStorageGranted;
  93. PowerManager.WakeLock wakeLock;
  94. LocationService gps;
  95. @Override
  96. public void onCreate (Bundle savedInstanceState)
  97. {
  98. super.onCreate(savedInstanceState);
  99. areaReferences = new ArrayList<>();
  100. areaReferences = readAreaReferencesFromPreferences();
  101. }
  102. @SuppressLint("InvalidWakeLockTag")
  103. public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  104. View root = inflater.inflate(R.layout.fragment_areas, container, false);
  105. //construct a FusedLocationProviderClient.
  106. mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(getActivity());
  107. //get permissions
  108. getLocationPermission();
  109. getReadStoragePermission();
  110. //instantiate area lists
  111. areaList = (ListView) root.findViewById(R.id.areaListView);
  112. allAreas = new ArrayList<>();
  113. //get saved areas
  114. allAreas = loadAreasFromPreferences();
  115. for (int i = 0; i < allAreas.size(); i++)
  116. {
  117. allAreas.get(i).setPathFile(areaReferences.get(i).getPath());
  118. }
  119. instantiateAreasList();
  120. PowerManager powerManager = (PowerManager) getContext().getSystemService(POWER_SERVICE);
  121. wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag");
  122. gps = new LocationService(getContext());
  123. //instantiate add button
  124. final FloatingActionButton fab = root.findViewById(R.id.fab_areas);
  125. fab.setOnClickListener(new View.OnClickListener() {
  126. @Override
  127. public void onClick(View view) {
  128. //permissions
  129. getLocationPermission();
  130. getWriteStoragePPermission();
  131. AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
  132. newArea = new OwnArea();
  133. newPositions = new ArrayList<>();
  134. final View viewInflated = LayoutInflater.from(getContext()).inflate(R.layout.area_input, (ViewGroup) getView(), false);
  135. builder.setView(viewInflated);
  136. final Button startTracking = viewInflated.findViewById(R.id.areaStartTracking);
  137. final Button stopTracking = viewInflated.findViewById(R.id.areaStopTracking);
  138. final Button addLocation = viewInflated.findViewById(R.id.areaAddGPSPoint);
  139. startTracking.setOnClickListener(new View.OnClickListener() {
  140. @Override
  141. public void onClick(View view) {
  142. //start tracking
  143. startLocationTracking();
  144. startTracking.setVisibility(View.INVISIBLE);
  145. stopTracking.setVisibility(View.VISIBLE);
  146. addLocation.setVisibility(View.INVISIBLE);
  147. }
  148. });
  149. stopTracking.setOnClickListener(new View.OnClickListener() {
  150. @Override
  151. public void onClick(View view) {
  152. //stop tracking
  153. List<LatLng> positionsToAdd = new ArrayList<>();
  154. positionsToAdd = gps.getPositions();
  155. for (LatLng pos: positionsToAdd)
  156. {
  157. newPositions.add(pos);
  158. }
  159. if (BuildConfig.DEBUG)
  160. {
  161. Log.d(TAG, "Received locations: " + newPositions.size());
  162. }
  163. wakeLock.release();
  164. startTracking.setVisibility(View.VISIBLE);
  165. stopTracking.setVisibility(View.INVISIBLE);
  166. addLocation.setVisibility(View.VISIBLE);
  167. }
  168. });
  169. addLocation.setOnClickListener(new View.OnClickListener() {
  170. @Override
  171. public void onClick(View view) {
  172. //get last known location
  173. getDeviceLocation();
  174. }});
  175. builder.setPositiveButton("Bestätigen", new DialogInterface.OnClickListener() {
  176. @Override
  177. public void onClick(DialogInterface dialog, int which) {
  178. final TextView titleView = viewInflated.findViewById(R.id.areaTitleUserInput);
  179. final TextView noticeView = viewInflated.findViewById(R.id.areaManagementNoticeUserInput);
  180. if (BuildConfig.DEBUG) {
  181. Log.d(TAG, "new title: " + titleView.getText());
  182. }
  183. if (titleView.getText().length()>0)
  184. {
  185. //save user input
  186. newArea.setTitle(String.valueOf(titleView.getText()));
  187. newArea.setNotice(String.valueOf(noticeView.getText()));
  188. newArea.setLocations(newPositions);
  189. newArea.calculateArea();
  190. boolean result = allAreas.add(newArea);
  191. if (BuildConfig.DEBUG)
  192. {
  193. Log.d(TAG, "new Task: " + newArea.toString());
  194. Log.d(TAG, "add new task result: " + result);
  195. }
  196. newArea.writeToExternalStorage(getContext());
  197. areaReferences.add(new AreaReference(newArea.getId(), newArea.getPathFile()));
  198. emptyPreferencesAndSaveAreaReferencesToPreferences();
  199. //actuate list
  200. instantiateAreasList();
  201. dialog.dismiss();
  202. //confirm added task
  203. Toast toast = Toast.makeText(getActivity(), "Grundstück hinzugefügt!", Toast.LENGTH_SHORT);
  204. TextView v = (TextView) toast.getView().findViewById(android.R.id.message);
  205. if( v != null)
  206. {
  207. //text align center
  208. v.setGravity(Gravity.CENTER);
  209. }
  210. toast.show();
  211. }
  212. else
  213. {
  214. //title needed
  215. Toast toast = Toast.makeText(getActivity(), "Grundstückstitel fehlt!", Toast.LENGTH_SHORT);
  216. TextView v = (TextView) toast.getView().findViewById(android.R.id.message);
  217. if( v != null)
  218. {
  219. //text align center
  220. v.setGravity(Gravity.CENTER);
  221. }
  222. toast.show();
  223. }
  224. }
  225. });
  226. builder.setNegativeButton("Abbrechen", new DialogInterface.OnClickListener() {
  227. @Override
  228. public void onClick(DialogInterface dialog, int which)
  229. {
  230. //reset variables
  231. newArea = new OwnArea();
  232. newPositions = new ArrayList<>();
  233. dialog.cancel();
  234. }
  235. });
  236. builder.show();
  237. }});
  238. return root;
  239. }
  240. /**
  241. * Get all stored areas and save them temporary.
  242. */
  243. public void instantiateAreasList()
  244. {
  245. final AreaAdapter adapter = new AreaAdapter(getActivity().getApplicationContext(), allAreas);
  246. adapter.registerDataSetObserver(new DataSetObserver() {
  247. @Override
  248. public void onChanged() {
  249. super.onChanged();
  250. if (BuildConfig.DEBUG)
  251. {
  252. Log.d(TAG, "onChanged");
  253. }
  254. if (BuildConfig.DEBUG)
  255. {
  256. Log.d(TAG, "dataset size: " + areaList.getAdapter().getCount());
  257. }
  258. if (areaList.getAdapter().getCount() > 0)
  259. {
  260. allAreas = new ArrayList<>();
  261. areaReferences =new ArrayList<>();
  262. for (int i = 0; i < areaList.getAdapter().getCount(); i++)
  263. {
  264. allAreas.add((OwnArea) areaList.getAdapter().getItem(i));
  265. if (BuildConfig.DEBUG)
  266. {
  267. Log.d(TAG, "dataset added: " + allAreas.get(i).toString());
  268. }
  269. areaReferences.add(new AreaReference(allAreas.get(i).getId(), allAreas.get(i).getPathFile()));
  270. }
  271. }
  272. }
  273. });
  274. areaList.setAdapter(adapter);
  275. //initialise onClickListeners
  276. areaList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
  277. @Override
  278. public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
  279. //for (int j = 0; j < adapterView.getChildCount(); j++)
  280. //adapterView.getChildAt(j).setBackgroundColor(Color.TRANSPARENT);
  281. // change the background color of the selected element
  282. //view.setBackgroundColor(Color.LTGRAY);
  283. //adapterView.setSelection(i);
  284. }});
  285. }
  286. @Override
  287. public void onPause() {
  288. super.onPause();
  289. //save area references to shared preferences
  290. emptyPreferencesAndSaveAreaReferencesToPreferences();
  291. }
  292. /**
  293. * Get OwnAreas from a JSONString.
  294. * @return
  295. */
  296. private List<OwnArea> loadAreasFromPreferences()
  297. {
  298. if (BuildConfig.DEBUG)
  299. {
  300. Log.d(TAG, "loadAreasFromPreferences() reference size: " + areaReferences.size());
  301. }
  302. List<OwnArea> areas = new ArrayList<>();
  303. Integer i = 0;
  304. for (AreaReference reference: areaReferences)
  305. {
  306. String jsonString = readAreaFromExternalStorage(reference.getPath());
  307. areas.add(new OwnArea(jsonString));
  308. if (BuildConfig.DEBUG)
  309. {
  310. Log.d(TAG, "load area from preferences: " + areas.get(i).toString());
  311. }
  312. i++;
  313. }
  314. return areas;
  315. }
  316. /**
  317. * Read OwnArea from file in external storage and return as a string.
  318. *
  319. * @param path File path where the OwnArea is saved.
  320. * @return
  321. */
  322. private String readAreaFromExternalStorage(String path)
  323. {
  324. if (BuildConfig.DEBUG)
  325. {
  326. Log.d(TAG, "readAreaFromExternalStorage()");
  327. }
  328. //Get the text file
  329. File file = new File(path);
  330. //Read text from file
  331. StringBuilder text = new StringBuilder();
  332. try {
  333. BufferedReader br = new BufferedReader(new FileReader(file));
  334. String line;
  335. while ((line = br.readLine()) != null) {
  336. text.append(line);
  337. if (BuildConfig.DEBUG)
  338. {
  339. Log.d(TAG, "Line: " + line);
  340. }
  341. }
  342. br.close();
  343. }
  344. catch (IOException e) {
  345. if (BuildConfig.DEBUG)
  346. {
  347. Log.e(TAG, "Failed read from external storage: " + e.toString());
  348. }
  349. }
  350. return text.toString();
  351. }
  352. /**
  353. * Converts an OwnArea object into a JSONString object.
  354. *
  355. * @param area Area to convert into JSONString
  356. * @return
  357. */
  358. public String areaToString(OwnArea area)
  359. {
  360. JSONObject areaObject = newArea.toJSONObject();
  361. return areaObject.toString();
  362. }
  363. /**
  364. * Reads areaReferences saved in preferences as jsonStrings
  365. *
  366. * @return list of AreaReferences
  367. */
  368. private List<AreaReference> readAreaReferencesFromPreferences() {
  369. if (BuildConfig.DEBUG)
  370. {
  371. Log.d(TAG, "readAreaReferencesFromPreferences()");
  372. }
  373. List<AreaReference> areas = new ArrayList<>();
  374. try {
  375. String jsonString = PreferenceManager.getDefaultSharedPreferences(getContext()).getString(KEY_AREA_REFERENCES, "error");
  376. if(!"error".equalsIgnoreCase(jsonString)) {
  377. JSONArray jsonObjects = new JSONArray(jsonString);
  378. for (int i = 0; i<jsonObjects.length();i++)
  379. {
  380. areas.add(new AreaReference(jsonObjects.getJSONObject(i)));
  381. // Find the root of the external storage.
  382. File root = android.os.Environment.getExternalStorageDirectory();
  383. //delete reference if file does not exist
  384. File file = new File(getContext().getFilesDir(), "meinWald" + File.pathSeparator + "areas" + File.pathSeparator + areas.get(i).getId() + ".txt");
  385. if(file.exists())
  386. {
  387. areas.remove(i);
  388. }
  389. }
  390. }
  391. else
  392. {
  393. if (BuildConfig.DEBUG)
  394. {
  395. Log.e(TAG, "read area reference error");
  396. }
  397. }
  398. } catch (JSONException e) {
  399. if (BuildConfig.DEBUG) {
  400. Log.e(TAG, "Error while parsing area references as jsonObjects from preferences");
  401. e.printStackTrace();
  402. }
  403. }
  404. for (AreaReference reference: areas)
  405. {
  406. if (BuildConfig.DEBUG)
  407. {
  408. Log.d(TAG, "read reference: " + reference.toString());
  409. }
  410. }
  411. return areas;
  412. }
  413. /**
  414. * Saves areas to preferences
  415. */
  416. private void emptyPreferencesAndSaveAreaReferencesToPreferences()
  417. {
  418. if (BuildConfig.DEBUG)
  419. {
  420. Log.d(TAG, "emptyPreferencesAndSaveAreaReferencesToPreferences()");
  421. }
  422. if (!areaReferences.isEmpty()) {
  423. if (BuildConfig.DEBUG) {
  424. Log.d(TAG, "areaReferences not empty");
  425. }
  426. PreferenceManager.getDefaultSharedPreferences(getContext()).edit().remove(KEY_AREA_REFERENCES).commit();
  427. JSONArray writeObjects = new JSONArray();
  428. for (AreaReference reference: areaReferences) {
  429. JSONObject object = reference.toJSONObject();
  430. writeObjects.put(object);
  431. if (BuildConfig.DEBUG) {
  432. Log.d(TAG, "area reference is " + object.toString());
  433. }
  434. }
  435. PreferenceManager.getDefaultSharedPreferences(getContext()).edit().putString(KEY_AREA_REFERENCES, writeObjects.toString()).commit();
  436. }
  437. else
  438. {
  439. if (BuildConfig.DEBUG) {
  440. Log.e(TAG, "area references are empty!");
  441. }
  442. }
  443. }
  444. /**
  445. * DOCU ME!
  446. * TOOD: What are grant results etc for?
  447. * @param requestCode
  448. * @param permissions
  449. * @param grantResults
  450. */
  451. @Override
  452. public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
  453. {
  454. if (BuildConfig.DEBUG) {
  455. Log.d(TAG, "onRequestPermissionResult Code: " + requestCode);
  456. }
  457. mLocationPermissionGranted = false;
  458. switch (requestCode) {
  459. case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
  460. // If request is cancelled, the result arrays are empty.
  461. if (grantResults.length > 0
  462. && grantResults[0] == PackageManager.PERMISSION_GRANTED)
  463. {
  464. mLocationPermissionGranted = true;
  465. }
  466. }
  467. case MY_CAMERA_PERMISSION_CODE: {
  468. if (grantResults.length > 0
  469. && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
  470. mCameraPermissionGranted = true;
  471. }
  472. }
  473. case READ_EXTERNAL_STORAGE_CODE: {
  474. if (grantResults.length > 0
  475. && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
  476. mReadStorageGranted = true;
  477. }
  478. }
  479. case WRITE_EXTERNAL_STORAGE_CODE: {
  480. if (grantResults.length > 0
  481. && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
  482. mWriteStorageGranted = true;
  483. }
  484. }
  485. }
  486. }
  487. public void getLocation(){
  488. wakeLock.acquire();
  489. gps = new LocationService(getContext());
  490. }
  491. /**
  492. * Get the best and most recent location of the device, which may be null in rare
  493. * cases when a location is not available.
  494. *
  495. */
  496. private void getDeviceLocation() {
  497. try {
  498. if (mLocationPermissionGranted) {
  499. Task<Location> locationResult = mFusedLocationProviderClient.getLastLocation();
  500. locationResult.addOnCompleteListener(getActivity(), new OnCompleteListener<Location>() {
  501. @Override
  502. public void onComplete(@NonNull Task<Location> task) {
  503. if (task.isSuccessful())
  504. {
  505. // Set the last known position to the current location of the device and add to tracking stack
  506. mLastKnownLocation = task.getResult();
  507. newPositions.add(new LatLng(mLastKnownLocation.getLatitude(),mLastKnownLocation.getLongitude()));
  508. if (BuildConfig.DEBUG) {
  509. if (task.getResult() != null)
  510. {
  511. Log.d(TAG, "getDeviceLocation: " + task.getResult().toString());
  512. Log.d(TAG, "Size: " + newPositions.size());
  513. }
  514. }
  515. } else {
  516. if (BuildConfig.DEBUG) {
  517. Log.d(TAG, "Current location is null. Using defaults.");
  518. Log.e(TAG, "Exception: %s", task.getException());
  519. }
  520. }
  521. }
  522. });
  523. }
  524. } catch (SecurityException e) {
  525. if (BuildConfig.DEBUG) {
  526. Log.e(TAG, "Exception occurred: ");
  527. e.printStackTrace();
  528. }
  529. }
  530. }
  531. public void startLocationTracking(){
  532. final Runnable runnable= new Runnable() {
  533. public void run() {
  534. // do stuff here
  535. getLocation();
  536. }
  537. };
  538. runnable.run();
  539. }
  540. /**
  541. * Request location permission, so that we can get the location of the device.
  542. * The result of the permission request is handled by a callback,
  543. * onRequestPermissionsResult.
  544. *
  545. */
  546. private void getLocationPermission() {
  547. if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(),
  548. android.Manifest.permission.ACCESS_FINE_LOCATION)
  549. == PackageManager.PERMISSION_GRANTED) {
  550. mLocationPermissionGranted = true;
  551. } else {
  552. ActivityCompat.requestPermissions(getActivity(),
  553. new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
  554. PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
  555. }
  556. }
  557. /**
  558. * Request read external storage permission, so that we can get saved images from external storage.
  559. * The result of the permission request is handled by a callback,
  560. * onRequestPermissionsResult.
  561. *
  562. */
  563. private void getReadStoragePermission() {
  564. if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(),
  565. Manifest.permission.READ_EXTERNAL_STORAGE)
  566. == PackageManager.PERMISSION_GRANTED) {
  567. mReadStorageGranted = true;
  568. } else {
  569. ActivityCompat.requestPermissions(getActivity(),
  570. new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE},
  571. READ_EXTERNAL_STORAGE_CODE);
  572. }
  573. }
  574. /**
  575. * Request read external storage permission, so that we can get saved images from external storage.
  576. * The result of the permission request is handled by a callback,
  577. * onRequestPermissionsResult.
  578. *
  579. */
  580. private void getWriteStoragePPermission() {
  581. if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(),
  582. Manifest.permission.WRITE_EXTERNAL_STORAGE)
  583. == PackageManager.PERMISSION_GRANTED) {
  584. mWriteStorageGranted = true;
  585. } else {
  586. ActivityCompat.requestPermissions(getActivity(),
  587. new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},
  588. WRITE_EXTERNAL_STORAGE_CODE);
  589. }
  590. }
  591. }