MyTracks 読み (9)

核心なソレを順に確認。
writeDocument メソドの先頭部分

  void writeDocument() {
    Log.d(MyTracksConstants.TAG, "Started writing track.");
    writer.writeHeader();

writer って何かというと定義が以下。

  private final TrackFormatWriter writer;

TrackFormatWriter は interface になっております。ええと TrackWriterFactory クラスに以下な記述があるんですが

  public enum TrackFileFormat {
    GPX {
      @Override
      TrackFormatWriter newFormatWriter(Context context) {
        return new GpxTrackWriter();
      }
    },
    KML {
      @Override
      TrackFormatWriter newFormatWriter(Context context) {
        return new KmlTrackWriter(context);
      }
    },
    CSV {
      @Override
      public TrackFormatWriter newFormatWriter(Context context) {
        return new CsvTrackWriter();
      }
    };

この enum は一体何だ。何を override してるのかが不明 (わら
ええと、ExportAllTracks で Dialog 作っている模様。

  private final DialogInterface.OnClickListener itemClick =
      new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
          switch (which) {
            case GPX_OPTION_INDEX:
              format = TrackFileFormat.GPX;
              break;
            case KML_OPTION_INDEX:
              format = TrackFileFormat.KML;
              break;
            case CSV_OPTION_INDEX:
              format = TrackFileFormat.CSV;
              break;
          }
        }
      };

ここで format がリセットされて (デフォは GPX な模様)、TrackWriter#writeTrack() に渡されているのか。で、TrackWriterFactory#newWriter() で

  public static TrackWriter newWriter(Context context,
      MyTracksProviderUtils providerUtils,
      Track track, TrackFileFormat format) {
    TrackFormatWriter writer = format.newFormatWriter(context);
    return new TrackWriter(context, providerUtils, track, writer);
  }

種別毎の TrackFormatWriter が戻されている模様。これも何かのパターンなのかな。具体的な処理が記述されているのが

  • GpxTrackWriter
  • KmlTrackWriter
  • CsvTrackWriter

の三つなカンジ。ここに具体的な処理が記述されてないと困る。例えば KML 用のヘッダ出力は以下な形になっている模様。

  @Override
  public void writeHeader() {
    if (pw != null) {
      pw.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
      pw.print("<kml");
      pw.print(" xmlns=\"http://earth.google.com/kml/2.0\"");
      pw.println(" xmlns:atom=\"http://www.w3.org/2005/Atom\">");
      pw.println("<Document>");
      pw.println("<atom:author><atom:name>My Tracks running on Android"
          + "</atom:name></atom:author>");
      pw.println("<name>" + StringUtils.stringAsCData(track.getName())
          + "</name>");
      pw.println("<description>"
          + StringUtils.stringAsCData(track.getDescription())
          + "</description>");
      writeStyles();
    }
  }

ざっくりベースな理解では微妙なので、

  • Track クラス
  • TrackBuffer クラス
  • Location クラス

あと、MyTracksProviderUtils#getTrackPoints() というメソドも確認必要。あら? Location は android の Location なのか。

って

色々確認してたんですが、出力はローカルだった事が判明。実機の中身を見てみたらデータが保存されておりました。よく見てみたら MyTracksMap な画面の右下にボタンが配置されているのを発見。
タップして出力されるメニューには_Send to Google..._というソレが御座いました。ナチュラルにも程があるなぁ。

ざっくり確認した所

MyTracksMap クラスの

  @Override
  public boolean onMenuItemSelected(int featureId, MenuItem item) {
    if (!super.onMenuItemSelected(featureId, item)) {
      if (selectedTrack != null) {
        MyTracks.getInstance().onActivityResult(
            MyTracksConstants.getActionFromMenuId(item.getItemId()), RESULT_OK,
            new Intent());
        return true;
      }
    }
    return false;
  }

にて MyTracks の onMenuItemSelected の以下の部分か。

      case MyTracksConstants.SEND_TO_GOOGLE_DIALOG: {
        shareRequested = false;
        showDialogSafely(DIALOG_SEND_TO_GOOGLE);
        break;
      }
      case MyTracksConstants.SEND_TO_GOOGLE: {
        if (results != null && resultCode == RESULT_OK) {
          final String mapid;
          final long trackId;
          if (results.hasExtra("mapid")) {
            mapid = results.getStringExtra("mapid");
          } else {
            mapid = "new";
          }
          if (results.hasExtra("trackid")) {
            trackId = results.getLongExtra("trackid", -1);
          } else {
            trackId = selectedTrackId;
          }
          final SendToMyMaps sender = new SendToMyMaps(this, mapid, auth,
              trackId, this/*progressIndicator*/);
          Runnable onCompletion = new Runnable() {
            public void run() {
              sendToMyMapsMessage = sender.getStatusMessage();
              sendToMyMapsSuccess = sender.wasSuccess();
              if (sendToMyMapsSuccess) {
                sendToMyMapsMapId = sender.getMapId();
                // Update the map id for this track:
                try {
                  Track track = providerUtils.getTrack(trackId);
                  track.setMapId(sender.getMapId());
                  providerUtils.updateTrack(track);
                } catch (RuntimeException e) {
                  // If that fails whatever reasons we'll just log an error, but
                  // continue.
                  Log.w(MyTracksConstants.TAG, "Updating map id failed.", e);
                }
              }
              if (sendToGoogleDialog.getSendToDocs()) {
                onActivityResult(MyTracksConstants.AUTHENTICATE_TO_DOCS,
                    RESULT_OK, new Intent());
              } else {
                dismissDialogSafely(DIALOG_PROGRESS);
                runOnUiThread(new Runnable() {
                  public void run() {
                    handleMapsFinish();
                  }
                });
              }
            }
          };
          sender.setOnCompletion(onCompletion);
          sender.run();
        } else {
          dismissDialogSafely(DIALOG_PROGRESS);
        }
        break;
      }

ナチュラルも程々に、というソレですな。
しかし showDialogSafely というメソドが定義されてて

  public void showDialogSafely(final int id) {
    runOnUiThread(new Runnable() {
      public void run() {
        try {
          showDialog(id);
        } catch (BadTokenException e) {
          Log.w(MyTracksConstants.TAG,
              "Could not display dialog with id " + id, e);
        } catch (IllegalStateException e) {
          Log.w(MyTracksConstants.TAG,
              "Could not display dialog with id " + id, e);
        }
      }
    });
  }

showDialog というメソドを探してしまったんですが、これって android.app.Activity のメソドな模様。この showDialog というメソドが呼ばれる時に一度だけその id で onCreateDialog なメソドが呼び出される模様。
手続き的には以下なあたりな模様。

      case DIALOG_SEND_TO_GOOGLE:
        sendToGoogleDialog = new SendToGoogleDialog(this);
        return sendToGoogleDialog;
      case DIALOG_SEND_TO_GOOGLE_RESULT:
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setIcon(android.R.drawable.ic_dialog_info);
        builder.setTitle("Title");
        builder.setMessage("Message");
        builder.setPositiveButton(getString(R.string.ok), null);
        builder.setNeutralButton(getString(R.string.share_map),
            new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog, int which) {
            shareLinkToMyMap(sendToMyMapsMapId);
            dialog.dismiss();
          }
        });
        sendToGoogleResultDialog = builder.create();
        return sendToGoogleResultDialog;

今更こんなあたりを掘っているのって微妙杉だろ。(とほほほ

とりあえず

帰ってヤりますorz

むむ

SEND_TO_DOCS だったorz

      case MyTracksConstants.SEND_TO_DOCS: {
        if (results != null && resultCode == RESULT_OK) {
          Log.d(MyTracksConstants.TAG, "Sending to Docs....");
          setProgressValue(50);
          setProgressMessage(getString(R.string.progress_message_sending_docs));
          final long trackId = results.getLongExtra("trackid", selectedTrackId);
          final SendToDocs sender = new SendToDocs(this, authMap.get("wise"),
              authMap.get("writely"), trackId);
          Runnable onCompletion = new Runnable() {
            public void run() {
              setProgressValue(100);
              dismissDialogSafely(DIALOG_PROGRESS);
              runOnUiThread(new Runnable() {
                public void run() {
                  sendToDocsMessage = sender.getStatusMessage();
                  sendToDocsSuccess = sender.wasSuccess();
                  handleMapsFinish();
                }
              });
            }
          };
          sender.setOnCompletion(onCompletion);
          sender.run();
        } else {
          dismissDialogSafely(DIALOG_PROGRESS);
        }
        break;
      }

これ、順を追って見てかないと微妙だな。つーか何故にここまで onActivityResult とかでチェインしてるのかも微妙。