void UUIDManager::Get(String &uuid) { result r = E_SUCCESS; String keyUUID("key_uuid"); AppRegistry* appRegistry = Application::GetInstance()->GetAppRegistry(); r = appRegistry->Get(keyUUID, uuid); if (r == E_KEY_NOT_FOUND) { String u; Tizen::Base::UuId* pUUID = Tizen::Base::UuId::GenerateN(); u.Append(pUUID->ToString().GetPointer()); appRegistry->Add(keyUUID, u); delete pUUID, pUUID = NULL; } r = appRegistry->Get(keyUUID, uuid); }
投稿者「admin」のアーカイブ
Tizenでデータを永続化する
SQLiteを使うまでのデータでない場合に、SharedPreferencesやNSUserDefaultのようなものが欲しくなる。Tizenでは以下のようにする。
#include <FApp.h>
using namespace Tizen::App;
result r = E_SUCCESS; String hogeKey("tmp_hoge_key"); String hogeValue("tmp_hoge_value"); String value(""); AppRegistry* appRegistry = Application::GetInstance()->GetAppRegistry(); r = appRegistry->Get(hogeKey, value); if (r == E_KEY_NOT_FOUND) { AppLog("value:%ls", value.GetPointer()); appRegistry->Add(hogeKey, hogeValue); } r = appRegistry->Get(hogeKey, value); AppLog("value:%ls", value.GetPointer());
以下のようなログが表示される。
virtual result HogeHoge::OnInitializing()(45) > value: virtual result HogeHoge::OnInitializing()(50) > value:tmp_hoge_value
virtual result HogeHoge::OnInitializing()(50) > value:tmp_hoge_value
TizenアプリでSQLiteを使う
SDKに同梱されているコードがいまいちわかりにくかったので、オフィシャルサイトにあるdocumentationからサンプルコードを拝借する。
■DBManager.cpp
とりあえず上から読んでいってSQLもしくはそれに準ずるものを探す。
result DBManager::CreateTable()
CREATE TABLE文がそのまま見つかったので読んでみる。
String sql; result r = E_SUCCESS; sql.Append(L"CREATE TABLE IF NOT EXISTS member(seq INTEGER PRIMARY KEY,id varchar(20),name varchar(20),age INTEGER)"); r = Execute(sql); AppLog("create : %s",GetErrorMessage(r)); return r;
SQL文を作ってそのままprivateメソッドに投げてるようだ。
result DBManager::Execute(String sql)
投げられたSQLをそのまま処理しているようだ。
__pDatabase->BeginTransaction(); r = __pDatabase->ExecuteSql(sql, true); __pDatabase->CommitTransaction();
__pDatabaseを操作している。
result DBManager::Open(String dbName)
__pDatabaseをインスタンス化している。use `dbname`;的なところでDBをopenしているところのようだ。
AppLog("Open"); __dbName = dbName; result r = E_SUCCESS; __pDatabase = new Database; __pDatabase->Construct(__dbName,true); return r;
bool DBManager::IsMember(String id)
以下のとおり取り出したデータはAndroidのCursorのようになっているようだ。
bool isMember = false; String sql; sql.Format(100,L"SELECT id FROM member where id = '%ls'",id.GetPointer()); // select a query using the Database::QueryN() wrapper AP DbEnumerator* pEnum = __pDatabase->QueryN(sql); if (pEnum) { while (pEnum->MoveNext() == E_SUCCESS) { isMember = true; } delete pEnum; } return isMember;
result DBManager::GetAllMember(ArrayList& list)
もう少しちゃんと取り出しているところを見る。
AppLog("GetAllMember"); result r = E_SUCCESS; String sql; sql.Format(50,L"select seq, id, name,age from member"); MEMBERINFO* pInfo = null; // select a query using the Database::QueryN() wrapper AP DbEnumerator* pEnum = __pDatabase->QueryN(sql); if (pEnum) { while (pEnum->MoveNext() == E_SUCCESS) { pInfo = new MEMBERINFO(); r = pEnum->GetIntAt(0, pInfo->seq); r = pEnum->GetStringAt(1,pInfo->id); r = pEnum->GetStringAt(2,pInfo->name); r = pEnum->GetIntAt(3,pInfo->age); list.Add(*pInfo); } delete pEnum; } return r;
サンプルコードが簡略化されていて理解しやすい。
■DBManager.h
このクラスはSingletonパターンになっていて以下のメソッドでインスタンスを取得する。
static DBManager* GetDB() { if(__pInstance == null) { __pInstance = new DBManager(); } return __pInstance; }
使い終わった時のメソッドも用意されている。
static void ReleaseDB() { if(__pInstance) { delete __pInstance; __pInstance = null; } }
コンストラクタ
DBManager::DBManager() :__pDatabase(null) { // TODO Auto-generated constructor stub Init(); }
void DBManager::Init()
Open(App::GetInstance()->GetAppRootPath() + L"data/mdb.db"); CreateTable();
次の2つのメソッドを呼び出している。
result DBManager::Open(String dbName)
引き数で与えられたデータベースファイルを開く。
AppLog("Open"); __dbName = dbName; result r = E_SUCCESS; __pDatabase = new Database; __pDatabase->Construct(__dbName,true); return r;
result DBManager::CreateTable()
CREATE TABLE文を実行する。
String sql; result r = E_SUCCESS; sql.Append(L"CREATE TABLE IF NOT EXISTS member(seq INTEGER PRIMARY KEY,id varchar(20),name varchar(20),age INTEGER)"); r = Execute(sql); AppLog("create : %s",GetErrorMessage(r)); return r;
デストラクタ
DBManager::~DBManager() { Close(); // TODO Auto-generated destructor stub }
result DBManager::Close()
AppLog("Close"); result r = E_SUCCESS; if(__pDatabase) { delete __pDatabase; __pDatabase = null; } return r;
■Form1.cpp
DBManagerの使い方は以下のようになっている。
GetDB()->GetAllMember(list);
result Form1::OnTerminating(void) { result r = E_SUCCESS; if(__pInfoPopup) { delete __pInfoPopup; __pInfoPopup = null; } ReleaseDB(); // TODO: Add your termination code here return r; }
TizenアプリでJSONをパースする
サンプルアプリのJsonParserAppを見る。
■JsonForm.cpp
void JsonForm::ParseAndDisplay(void)
// なるべく簡略化したいのでエラー処理はコメントアウトしておく。 // fileを読み込み専用で開く。 File file; String filePath = App::GetInstance()->GetAppRootPath() + L"data/jsonSample.json"; result r = file.Construct(filePath, L"r"); #TryReturnVoid(r == E_SUCCESS, "file construction failure with [%s]", GetErrorMessage(r)); FileAttributes att; r = File::GetAttributes(filePath, att); #TryReturnVoid(r == E_SUCCESS, "file GetAttributes failure with [%s]", GetErrorMessage(r)); long long size = att.GetFileSize(); #TryReturnVoid(size > 0, "file does not contain valid data, size of file [%ld]", size); ByteBuffer buf; r = buf.Construct(size + 1);// fileサイズ+1で初期化 #TryReturnVoid(r == E_SUCCESS, "bytebuffer construct failure with [%s]", GetErrorMessage(r)); r = file.Read(buf);// fileを読み込む #TryReturnVoid(r == E_SUCCESS, "file read failure with [%s]", GetErrorMessage(r)); // 読み込んだデータをJSONにパース IJsonValue* pJson = JsonParser::ParseN(buf); TryCatch(pJson, , "ParseN failed with [%s]", GetErrorMessage(GetLastResult())); AppLog("Before traverse %d", _pList->GetItemCount()); _pJsonKeyList->RemoveAll(true); _pValueList->RemoveAll(true); TraverseFunction(pJson); AppLog("After traverse");
fileにclose的なものがないけどいいのかな。
void JsonForm::TraverseFunction(IJsonValue* pValue)
パースしたIJsonValueのオブジェクトを実際にどう扱うか見てみる。このメソッドは、pValue->GetType()で分岐してある。typeによっては自身を呼び出し再帰処理している。
FWebJsonIJsonValue.h
jsonの値の型は以下のように定義されている。
enum JsonType { JSON_TYPE_STRING, /**< The JSON string type*/ JSON_TYPE_NUMBER, /**< The JSON number type*/ JSON_TYPE_OBJECT, /**< The JSON object type*/ JSON_TYPE_ARRAY, /**< The JSON array type*/ JSON_TYPE_BOOL, /**< The JSON bool type*/ JSON_TYPE_NULL /**< The JSON null type*/ };
nullの時
TryReturnVoid(_pList, "_pList is null"); TryReturnVoid(pValue, "input jsonvalue pointer is null");
オブジェクトの時
Mapにしてkeyとvalueを取り出し、valueを引き数にして再帰呼び出ししている。
case JSON_TYPE_OBJECT: { JsonObject* pObject = static_cast< JsonObject* >(pValue); IMapEnumeratorT< const String*, IJsonValue* >* pMapEnum = pObject->GetMapEnumeratorN(); while (pMapEnum->MoveNext() == E_SUCCESS) { const String* key = null; IJsonValue* value = null; pMapEnum->GetKey(key); String* pListKey = new (std::nothrow) String(*key); _pJsonKeyList->Add(*pListKey); String* pStr = null; _isArray = 0; pMapEnum->GetValue(value); if (value->GetType() == JSON_TYPE_OBJECT) { pStr = new (std::nothrow) String("Value is an Object"); _pValueList->Add(*pStr); } else if (value->GetType() == JSON_TYPE_ARRAY) { pStr = new (std::nothrow) String("Value is an Array"); _pValueList->Add(*pStr); } TraverseFunction(value); } delete pMapEnum; } break;
文字列の場合
_pValueListに追加している。
case JSON_TYPE_STRING: { JsonString* pVal = static_cast< JsonString* >(pValue); if (_isArray == 0) { String* pStr = new (std::nothrow) String(*pVal); _pValueList->Add(*pStr); } } break;
配列の場合
keyとvalueを取り出し、valueを引き数にして再帰呼び出ししている。
case JSON_TYPE_ARRAY: { JsonArray* pJsonArray = static_cast< JsonArray* >(pValue); pJsonArray->GetCount(); IEnumeratorT< IJsonValue* >* pEnum = pJsonArray->GetEnumeratorN(); while (pEnum->MoveNext() == E_SUCCESS) { IJsonValue* pValue = null; pEnum->GetCurrent(pValue); if ((pValue->GetType() == JSON_TYPE_STRING) || (pValue->GetType() == JSON_TYPE_NUMBER) || (pValue->GetType() == JSON_TYPE_BOOL) || (pValue->GetType() == JSON_TYPE_NULL)) _isArray = 1; TraverseFunction(pValue); } delete pEnum; } break;
数値の場合
JsonNumberをtoStringして文字列にし、_pValueListにaddしている。
case JSON_TYPE_NUMBER: { JsonNumber* pVal = static_cast< JsonNumber* >(pValue); String* pStr = new (std::nothrow) String((pVal->ToString())); if (_isArray == 0) _pValueList->Add(*pStr); } break;
真偽値の場合
条件分岐して、文字列を_pValueListにaddするようにしている。
case JSON_TYPE_BOOL: { String* pStr = null; JsonBool* pVal = static_cast< JsonBool* >(pValue); if (*pVal == true) pStr = new (std::nothrow) String("true"); else pStr = new (std::nothrow) String("false"); if (_isArray == 0) _pValueList->Add(*pStr); } break;
nullの場合
nullという文字列を_pValueListにaddするようにしている。
case JSON_TYPE_NULL: { String* pStr = null; pStr = new (std::nothrow) String("null"); if (_isArray == 0) _pValueList->Add(*pStr); } break;
読むのが面倒だったがC++の基本が分かる良いコードだった。
TizenアプリでHTTP通信する
サンプルアプリのHttpClientを見る。
■MainForm.cpp
MainFormはTizen::Net::Http::IHttpTransactionEventListenerを継承している。
result MainForm::RequestHttpGet(void)
エラー処理を省くと以下の通りとなる。
HttpTransaction* pHttpTransaction = null; HttpRequest* pHttpRequest = null; pHttpTransaction = __pHttpSession->OpenTransactionN(); r = pHttpTransaction->AddHttpTransactionListener(*this); pHttpRequest = const_cast< HttpRequest* >(pHttpTransaction->GetRequest()); r = pHttpRequest->SetUri(HTTP_CLIENT_REQUEST_URI); r = pHttpRequest->SetMethod(NET_HTTP_METHOD_GET); r = pHttpTransaction->Submit();
AddHttpTransactionListenerの引き数はIHttpTransactionEventListenerを継承したクラスでサンプルアプリでは自身である。
void MainForm::OnTransactionReadyToRead(HttpSession& httpSession, HttpTransaction& httpTransaction, int availableBodyLen)
通信結果を受け取る。
HttpResponse* pHttpResponse = httpTransaction.GetResponse(); if (pHttpResponse->GetHttpStatusCode() == HTTP_STATUS_OK) { HttpHeader* pHttpHeader = pHttpResponse->GetHeader(); if (pHttpHeader != null) { String* tempHeaderString = pHttpHeader->GetRawHeaderN(); ByteBuffer* pBuffer = pHttpResponse->ReadBodyN(); String text(L"Read Body Length: "); text.Append(availableBodyLen); __pEditArea->SetText(text); Draw(); delete tempHeaderString; delete pBuffer; } }
IHttpTransactionEventListenerを継承した場合は以下のメソッドの実装が必要になるっぽい。
- void MainForm::OnTransactionReadyToRead(HttpSession& httpSession, HttpTransaction& httpTransaction, int availableBodyLen)
- void MainForm::OnTransactionAborted(HttpSession& httpSession, HttpTransaction& httpTransaction, result r)
- void MainForm::OnTransactionReadyToWrite(HttpSession& httpSession, HttpTransaction& httpTransaction, int recommendedChunkSize)
- void MainForm::OnTransactionHeaderCompleted(HttpSession& httpSession, HttpTransaction& httpTransaction, int headerLen, bool authRequired)
- void MainForm::OnTransactionCompleted(HttpSession& httpSession, HttpTransaction& httpTransaction)
- void MainForm::OnTransactionCertVerificationRequiredN(HttpSession& httpSession, HttpTransaction& httpTransaction, Tizen::Base::String* pCert)
パーティショニングする
以下のクエリを実行する。但し、TIMESTAMP型はMySQLのバージョンによってはバグがあってTIMESTAMP型のカラムでパーティショニングできないのでdatetime型などに変更する必要がある。
ALTER TABLE `log` PARTITION BY RANGE columns (created) ( PARTITION p20130101 VALUES LESS THAN ('2013-01-01 00:00:00'), PARTITION p20130201 VALUES LESS THAN ('2013-02-01 00:00:00'), PARTITION p20130301 VALUES LESS THAN ('2013-03-01 00:00:00'), PARTITION p20130401 VALUES LESS THAN ('2013-04-01 00:00:00'), PARTITION p20130501 VALUES LESS THAN ('2013-05-01 00:00:00'), PARTITION p20130601 VALUES LESS THAN ('2013-06-01 00:00:00'), PARTITION p20130701 VALUES LESS THAN ('2013-07-01 00:00:00'), PARTITION p20130801 VALUES LESS THAN ('2013-08-01 00:00:00'), PARTITION p20130901 VALUES LESS THAN ('2013-09-01 00:00:00'), PARTITION p20131001 VALUES LESS THAN ('2013-10-01 00:00:00'), PARTITION p20131101 VALUES LESS THAN ('2013-11-01 00:00:00'), PARTITION p20131201 VALUES LESS THAN ('2013-12-01 00:00:00'), PARTITION p20140101 VALUES LESS THAN ('2014-01-01 00:00:00'), PARTITION p20140201 VALUES LESS THAN ('2014-02-01 00:00:00'), PARTITION p20140301 VALUES LESS THAN ('2014-03-01 00:00:00'), PARTITION p20140401 VALUES LESS THAN ('2014-04-01 00:00:00'), PARTITION p20140501 VALUES LESS THAN ('2014-05-01 00:00:00'), PARTITION p20140601 VALUES LESS THAN ('2014-06-01 00:00:00'), PARTITION p20140701 VALUES LESS THAN ('2014-07-01 00:00:00'), PARTITION p20140801 VALUES LESS THAN ('2014-08-01 00:00:00'), PARTITION p20140901 VALUES LESS THAN ('2014-09-01 00:00:00'), PARTITION p20141001 VALUES LESS THAN ('2014-10-01 00:00:00'), PARTITION p20141101 VALUES LESS THAN ('2014-11-01 00:00:00'), PARTITION p20141201 VALUES LESS THAN ('2014-12-01 00:00:00'), PARTITION pmax VALUES LESS THAN MAXVALUE );
パーティションを指定してデータを削除するには以下のクエリを実行する。
Alter table log drop partition p20130101;
データはそのままでテーブルのパーティショニングを除去するには以下のクエリを実行する。
ALTER TABLE log REMOVE PARTITIONING;
以下のクエリでパーティションを確認する。
SELECT TABLE_SCHEMA, TABLE_NAME, PARTITION_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='log';
iOSでOpenSSLを使って大きな数値計算をする
桁あふれしそうな数の計算をする。
■OpenSSLをiOS用にビルド
git clone https://github.com/x2on/OpenSSL-for-iPhone.git cd OpenSSL-for-iPhone/ ./build-libssl.sh
ビルドされたライブラリとヘッダーファイルをプロジェクトに追加する。
mkdir ../MyProject/Library/OpenSSL cp -r include/ ../MyProject/Library/OpenSSL/include cp -r lib/ ../MyProject/Library/OpenSSL/lib
Build Settings
Header Search Path
以下を追加する。
$(SRCROOT)/MyProject/Library/OpenSSL/include
Library Search Path
以下を追加する。
"$(SRCROOT)/MyProject/Library/OpenSSL/lib"
Build Phases
Link Binary With Libraries
libcrypto.aとlibssl.aを追加する。
■実装
#import <openssl/bn.h> unsigned int rand = arc4random() % 100000000; BIGNUM *random = BN_new();BN_set_word(random, rand); BIGNUM *base = BN_new();BN_set_word(base, BASE); BIGNUM *prime = BN_new();BN_set_word(prime, PRIME); BIGNUM *remainder = BN_new(); BN_CTX *ctx; ctx = BN_CTX_new(); BN_mod_exp(remainder, base, random, prime, ctx); BN_CTX_free(ctx);
iOSでPythonが動けばいいのに。
参考
mozc for Androidにトグルが一定時間で確定される機能を追加する
mozc本体のコメントに将来的にそういった機能をつけるような事が書かれていて、その時コンフリクトする事が予想される。
■クライアント側
以下のように定義し、ViewManager.javaでタイマーでコマンドが実行されるようにする。
ViewManager.java
private final int keycodeKaomojiToggleCommit;
keycodeKaomojiToggleCommit = res.getInteger(R.integer.key_kaomoji_toggle_commit);
とりあえず定義だけ上述のようにする。タイマー部分はよきに計らってやる。
KeycodeConverter.java
public static final ProtoCommands.KeyEvent KAOMOJI_TOGGLE_COMMIT = ProtoCommands.KeyEvent.newBuilder().setSpecialKey(SpecialKey.KAOMOJI_TOGGLE_COMMIT).build();
keycode.xml
<integer name="key_kaomoji_toggle_commit">-10025</integer>
ProtoCommands.java
サーバー側をビルドすると生成される。
■サーバー側
composer/composer.cc
実装しようとしている機能はカーソルを右に動かす動作と非常に似ている。そしてカーソルを動かす処理はこのファイルの以下のメソッドである。
void Composer::MoveCursorRight() { if (position_ < composition_->GetLength()) { ++position_; } UpdateInputMode(); typing_corrector_.Invalidate(); }
そこでpositionを移動させない関数を追加する。引き数で条件分岐してもいいのだが右に移動させる機能とトグルをコミットさせる機能は本質的に別物であるので別にする。コンフリクトすると面倒なだけでもある。
void Composer::KaomojiToggleCommit() { UpdateInputMode(); typing_corrector_.Invalidate(); }
composer/composer.h
void KaomojiToggleCommit();
次に上述を呼び出す処理を実装する。
session/session.h
bool KaomojiToggleCommit(mozc::commands::Command *command);
session/session.cc
bool Session::KaomojiToggleCommit(commands::Command *command) { if (context_->GetRequest().crossing_edge_behavior() == commands::Request::COMMIT_WITHOUT_CONSUMING && context_->composer().GetLength() == context_->composer().GetCursor()) { Commit(command); // Do not consume. command->mutable_output()->set_consumed(false); return true; } command->mutable_output()->set_consumed(true); if (CommitIfPassword(command)) { return true; } context_->mutable_composer()->KaomojiToggleCommit(); if (Suggest(command->input())) { Output(command); return true; } OutputComposition(command); return true; }
コピペで申し訳ない限りである。このメソッドは同ファイルの以下の部分から呼び出される。
case keymap::CompositionState::MOVE_CURSOR_RIGHT: return MoveCursorRight(command); case keymap::CompositionState::KAOMOJI_TOGGLE_COMMIT: return KaomojiToggleCommit(command); case keymap::CompositionState::MOVE_CURSOR_TO_BEGINNING: return MoveCursorToBeginning(command);
定義したメソッドがクライアントからのコマンドで呼び出されるようにする。
■CompositionState
以下のようにCompositionStateで実行されるコマンドの定義と登録をする。
session/internal/keymap_interface.h
MOVE_CURSOR_RIGHT, KAOMOJI_TOGGLE_COMMIT, MOVE_CURSOR_TO_BEGINNING,
session/internal/keymap.cc
以下のようにして、コマンド名KaomojiToggleCommitで、CompositionState::KAOMOJI_TOGGLE_COMMITが実行されるようになる。
RegisterCompositionCommand("KaomojiToggleCommit", CompositionState::KAOMOJI_TOGGLE_COMMIT);
data/keymap/mobile.tsv
以下のようにして、KaomojiToggleCommitキーでKaomojiToggleCommitコマンドが実行される。
Composition Right MoveCursorRight Composition KaomojiToggleCommit KaomojiToggleCommit Composition Space Convert
一番左の列はstatusなのだがIME全体で入力の状態というものが存在するという事を理解しておく必要がある。
■Specialキーの追加とKeyEvent
強引ではあるがトグルをコミットさせる(実際には視認できない)KaomojiToggleCommitキーを追加する。
session/commands.proto
下のように記述して定義する。ビルドした時にKAOMOJI_TOGGLE_COMMITが追加されたProtoCommands.javaが生成され、クライアント側からSpecialKeyのKAOMOJI_TOGGLE_COMMITを叩ける。
COMMA = 70; // Numpad [,] KAOMOJI_TOGGLE_COMMIT = 71; NUM_SPECIALKEYS = 72;
data/usage_stats/stats.def
追加したSpecialKeyなどがusage stats用のリストに存在せず、Debugビルドするとトグルがコミットされた時に落ちるので、以下のように追加する。
Performed_Composition_KaomojiToggleCommit
# Virtual Key for software keyboard KAOMOJI_TOGGLE_COMMIT
この定義により、今回のキーとコマンドがusage_stats_list.hに追加される。
commands.protoから、commands.pb.hとcommands.pb.ccが生成されるが、キー操作がフックされるために以下の2ファイルの書き換えが必要となる。
session/random_keyevents_generator.cc
commands.pb.hがincludeされ以下のようにkSpecialKeysの配列ができる。
commands::KeyEvent::RIGHT, commands::KeyEvent::KAOMOJI_TOGGLE_COMMIT, commands::KeyEvent::UP,
session/key_parser.cc
keycode_map_["right"] = KeyEvent::RIGHT; keycode_map_["kaomojitogglecommit"] = KeyEvent::KAOMOJI_TOGGLE_COMMIT; keycode_map_["enter"] = KeyEvent::ENTER;
SessionCommandの追加
都合によりSpecialKeyを追加したが本来ならばSessionCommandの追加で特に問題はない。
data/usage_stats/stats.def
SendCommand_KaomojiToggleCommit
session/commands.proto
以下のようにしてSessionCommandを追加できる。
KAOMOJI_TOGGLE_COMMIT = 24; // Number of commands. // When new command is added, the command should use below number // and NUM_OF_COMMANDS should be incremented. NUM_OF_COMMANDS = 25;
session/session.cc
以下のようにしてSessionCommandをフックする。
case commands::SessionCommand::KAOMOJI_TOGGLE_COMMIT: result = KaomojiToggleCommit(command); break;
上述のようにするとSessionExecutorから以下のように呼び出せる。
public void toggleCommit(int candidateId, EvaluationCallback callback) { Input.Builder inputBuilder = Input.newBuilder() .setType(CommandType.SEND_COMMAND) .setCommand(SessionCommand.newBuilder() .setType(SessionCommand.CommandType.KAOMOJI_TOGGLE_COMMIT) .setId(candidateId)); evaluateAsynchronously(inputBuilder, null, callback); }
■ダウンロード
Tizenでクリップボードを使う
現状ではJavaScriptから操作する事ができない。
String *pText = static_cast<String *>(pMessage->GetValue(String(L"text"))); ClipboardItem item; item.Construct(CLIPBOARD_DATA_TYPE_TEXT, pText); Clipboard *pClipboard = Clipboard::GetInstance(); pClipboard->CopyItem(item);
今月は記事を一つも書いてないので間に合わせ。
Androidでキーボードの設定画面に遷移させる
設定画面から遷移できるキーボードを有効化する画面に遷移する。
Intent intent = new Intent(); intent.setAction(Settings.ACTION_INPUT_METHOD_SETTINGS); startActivity(intent);
入力に使用するキーボードを選択するダイアログを表示する。
InputMethodManager inputMethodManager = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); inputMethodManager.showInputMethodPicker();
任意のパッケージ名のInputMethodが有効化されているか判定する。
private boolean isEnabled(Context context) { InputMethodManager inputMethodManager = InputMethodManager.class.cast( context.getSystemService(Context.INPUT_METHOD_SERVICE) ); if (inputMethodManager == null) { Log.i("InputMethodManager", "not found."); return false; } String packageName = context.getPackageName(); // 有効なInputMethod一覧に任意のパッケージ名が含まれているか確認する for (InputMethodInfo inputMethodInfo : inputMethodManager.getEnabledInputMethodList()) { if (inputMethodInfo.getServiceName().startsWith(packageName)) { return true; } } return false; }
任意のパッケージ名のInputMethodが入力方法として選択されているかどうか判定する。
private boolean isDefault(Context context) { InputMethodInfo info = null; InputMethodManager inputMethodManager = InputMethodManager.class.cast( context.getSystemService(Context.INPUT_METHOD_SERVICE) ); if (inputMethodManager == null) { Log.i("InputMethodManager", "not found."); return false; } String packageName = context.getPackageName(); // InputMethod一覧に任意のパッケージ名が含まれているか確認する for (InputMethodInfo inputMethodInfo : inputMethodManager.getInputMethodList()) { if (inputMethodInfo.getPackageName().equals(packageName)) { info = inputMethodInfo; } } if (info == null) { Log.i("InputMethodInfo", "not found."); return false; } // infoのidと現在有効になってるIMEのidを比較する String currentIme = android.provider.Settings.Secure.getString( context.getContentResolver(), android.provider.Settings.Secure.DEFAULT_INPUT_METHOD ); return info.getId().equals(currentIme); }