태그 보관물: android

안드로이드 장치에서 이메일 주소 읽어오기

안드로이드 앱에서 사용자의 이메일 주소를 읽어오는 방법입니다.

회원가입시에 미리 입력 시켜둬서 사용자 편의성을 높이는데 사용할 수 있으며 악용하진 말아야할 것 입니다.

 

1. AccountManager 사용하기 (API 5 이상)

AccountManager를 이용하면  기기에 등록된 모든 계정이름을 불러올 수 있고 계정이름이 이메일인 경우가 많기 때문에 활용할 수 있습니다.

Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
Account[] accounts = AccountManager.get(context).getAccounts();
for (Account account : accounts) {
    if (emailPattern.matcher(account.name).matches()) {
        String possibleEmail = account.name;
        ...
    }
}

AccountManager를 사용하려면 GET_ACCOUNTS 권한이 필요하니 AndroidManifest.xml에 권한을 추가해둬야 합니다.

<uses-permission android:name="android.permission.GET_ACCOUNTS" />

 

2. ContactsContract.Profile 이용하기 (API 14 이상)

ICS부터는 사용자의 프로필에 접근하여 이메일을 가져올 수 있습니다.

public class ExampleActivity extends Activity implements LoaderManager.LoaderCallbacks<Cursor> {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getLoaderManager().initLoader(0, null, this);
    }
 
    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle arguments) {
        return new CursorLoader(this,
                // Retrieve data rows for the device user's 'profile' contact.
                Uri.withAppendedPath(
                        ContactsContract.Profile.CONTENT_URI,
                        ContactsContract.Contacts.Data.CONTENT_DIRECTORY),
                ProfileQuery.PROJECTION,
 
                // Select only email addresses.
                ContactsContract.Contacts.Data.MIMETYPE + " = ?",
                new String[]{ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE},
 
                // Show primary email addresses first. Note that there won't be
                // a primary email address if the user hasn't specified one.
                ContactsContract.Contacts.Data.IS_PRIMARY + " DESC");
    }
 
    @Override
    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
        List<String> emails = new ArrayList<String>();
        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            emails.add(cursor.getString(ProfileQuery.ADDRESS));
            // Potentially filter on ProfileQuery.IS_PRIMARY
            cursor.moveToNext();
        }
 
        ...
    }
 
    @Override
    public void onLoaderReset(Loader<Cursor> cursorLoader) {
    }
 
    private interface ProfileQuery {
        String[] PROJECTION = {
                ContactsContract.CommonDataKinds.Email.ADDRESS,
                ContactsContract.CommonDataKinds.Email.IS_PRIMARY,
        };
 
        int ADDRESS = 0;
        int IS_PRIMARY = 1;
    }
}

READ_PROFILEREAD_CONTACTS의 두 가지 권한이 필요합니다.

<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />

참조 : How to get the Android device’s primary e-mail address

수동으로 AVD 삭제하기

“The android virtual device XXX is currently running in an emulator and cannot be deleted”라며 Android Virtual Device Manager에서 AVD를 삭제하지 못할 경우에는

사용자의 홈디렉토리로 가서 .android 디렉토리 아래의 avd 디렉토리에서 해당 AVD의 .avd와 .ini 파일을 삭제해버리면 된다.
(~/.android/avd/*.avd, *.ini)

Unable to build: Could not find dx.jar file

갑자기 Eclipse에서 안드로이드 소스 빌드가 되지 않았는데 다음과 같은 에러가 발생:

Unable to build: Could not find dx.jar file

구글링을 해보니 Android SDK Platform-tools를 지웠다 다시 깔아보고 clean후에 빌드하라고 하는데 해결이 되지 않았다.

그리고
'Installing this package also requires installing: - Missing SDK Platform Android, API 17'라면서 Android 4.2 (API 17)이 설치가 되지 않는 문제도 있었는데

찾아보니 Android SDK Manager 설정에서 ‘Clear Cache’를 하고 PackagesReload를 하니 업데이트된 Android SDK Platform-tools와 API 17이 나타나는 것이 아닌가.
아무래도 Android SDK Manager 내부의 캐시가 꼬였던 것인지 문제가 되었던것 같다.

오늘의 삽질 – AlertDialog의 EditText에 키보드 보여주기

AlertDialog에 넣었던 EditText에서 포커스는 가있어도 소프트웨어 키보드가 나타나지 않는 증상이 있어서
구글링을 통해 온갖 키보드를 나타내기 위한 시도를 하였다.

final View innerView = View.inflate(MainActivity.this, R.layout.name_edit_popup, null);
final EditText editText = (EditText)innerView.findViewById(R.id.nameEdit);
 
final AlertDialog dialog = new AlertDialog.Builder(MainActivity.this)
	.setCustomTitle(innerView)
	.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
 
		@Override
		public void onClick(DialogInterface dialog, int which) {
			// something
		}
	}).create();
 
// 시도 1
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
 
// 시도 2
editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (hasFocus) {
            dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
        }
    }
});
 
// 시도 3
dialog.setOnShowListener(new OnShowListener() {
 
    @Override
    public void onShow(DialogInterface dialog) {
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
    }
});
 
dialog.show();

그런데도 키보드가 나타나지 않아서 멘붕하고 있었는데…


...
final AlertDialog dialog = new AlertDialog.Builder(MainActivity.this)
.setCustomTitle(innerView)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
...

setView가 아니라 setCustomTitle을 사용하고 있었음을 발견하였다…

CustomTitle에 넣은 EditText에서는 키보드를 보여주지 않는 듯하니 참고하길

DB error while creating CookieSyncManager

If the app has services, or other processes, then you can see this kind of error when using CookieSyncManager.

01-13 16:44:46.674: E/Database(4298): CREATE TABLE android_metadata failed
01-13 16:44:46.690: E/Database(4298): Failed to setLocale() when constructing, closing the database
01-13 16:44:46.690: E/Database(4298): android.database.sqlite.SQLiteException: database is locked
01-13 16:44:46.690: E/Database(4298): at android.database.sqlite.SQLiteDatabase.native_setLocale(Native Method)
01-13 16:44:46.690: E/Database(4298): at android.database.sqlite.SQLiteDatabase.setLocale(SQLiteDatabase.java:2113)
01-13 16:44:46.690: E/Database(4298): at android.database.sqlite.SQLiteDatabase.(SQLiteDatabase.java:1966)
01-13 16:44:46.690: E/Database(4298): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:887)
01-13 16:44:46.690: E/Database(4298): at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:965)
01-13 16:44:46.690: E/Database(4298): at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:958)
01-13 16:44:46.690: E/Database(4298): at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:576)
01-13 16:44:46.690: E/Database(4298): at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:203)
01-13 16:44:46.690: E/Database(4298): at android.webkit.WebViewDatabase.getInstance(WebViewDatabase.java:214)
01-13 16:44:46.690: E/Database(4298): at android.webkit.WebSyncManager.(WebSyncManager.java:65)
01-13 16:44:46.690: E/Database(4298): at android.webkit.CookieSyncManager.(CookieSyncManager.java:69)
01-13 16:44:46.690: E/Database(4298): at android.webkit.CookieSyncManager.createInstance(CookieSyncManager.java:96)

This happens because the DB created inside the CookieSyncManager is accessible from only one process.
I couldn’t find the way to use the CookieSyncManager from more than one process.

Also, I tried to CookieSyncManager.createInstance() from one process and CookieSyncManager.getInstance() from another, but it didn’t work.

I should have to solve this problem by only using the CookieSyncManager from one process.
Also keep in mind that CookieManager requires CookieSyncManager to work.