10 Май 2009

Использование стандартного UI для поиска.

Цель

В результате мы хотим получить нечто похожее на:
searchsample

Редактирование AndroidManifest.xml

Для активации этого окошка необходимо прописать следующий код для вашего активити.

  1. Настройка окна поиска
    <meta-data android:name="android.app.searchable"
     android:resource="@xml/searchable" />
    

    Где, xml/searchable - это XML примерно следующего содержания: 

    <searchable xmlns:android="http://schemas.android.com/apk/res/android"
     android:label="Заголовок окна"
     android:hint="Текст на фоне поля ввода"
     android:searchMode="showSearchLabelAsBadge"
    />
    

    Подробнее про этот файл в разделе Searchability Metadata в доках

  2. Настройка активити для получения результатов необходимо добавить Intent-Filter:
    <intent-filter>
     <action android:name="android.intent.action.SEARCH" />
     <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    

Получение введенного значения

Для получения результатов запроса достаточно написать следующий код в onCreate:

if (Intent.ACTION_SEARCH.equals(getIntent().getAction()))
{
	String query = getIntent().getStringExtra(SearchManager.QUERY);
}

6 Апрель 2009

Ручной Scroll в Андроиде

Наверное, каждый задавался себе вопросом - как же необходимо скроллить, что бы ощущения были такие же как в приложениях Maps и Browser. И вот я хочу вам представить готовый рецепт, основанный на коде WebView.

Для этого будем использовать два класса - Scroller и VelocityTracker.

Первое, что нам нужно сделать - начать считать скорость и сохранять её. Приведу сразу код:

//Экземпляр VelocityTracker
//для подсчета скоростей
VelocityTracker mVelocityTracker;

//Переменные для сохранения координат, полученных при предыдущих
//вызовах onTouchEvent
int oldX = -1, oldY = -1;

//Переменные для смещения посчитанного
int dx = 0, dy = 0;

@Override
public boolean onTouchEvent(MotionEvent ev) {
	int action = ev.getAction();
	switch (action) {
	case MotionEvent.ACTION_DOWN: {
		//Получаем новый экземпляр VelocityTracker.obtain()
		//Я не пробовал получать иначе, но в исходниках
		//было именно так. Скорее всего можно
		//просто вызывать VelocityTracker.clear();
		mVelocityTracker = VelocityTracker.obtain();

		oldX = (int) ev.getX();
		oldY = (int) ev.getY();
		return true;
	}
	case MotionEvent.ACTION_MOVE: {
		//Необходимо вызывать этот код в ACTION_MOVE, ACTION_UP и
		//возможно еще в ACTION_DOWN
		mVelocityTracker.addMovement(ev);

		int deltaX = (int) (oldX - ev.getX());
		int deltaY = (int) (oldY - ev.getY());

		oldX = (int) ev.getX();
		oldY = (int) ev.getY();

		//Делаем скролл на нужное смещение.
		//Этот метод только для ACTION_MOVE.
		mScroller.startScroll(dx, dy, -deltaX, -deltaY);
		return true;
	}
	case MotionEvent.ACTION_UP: {
		mVelocityTracker.addMovement(ev);

		//Считаем скорость. 1000 пикселей в секунду -
		//средняя ожидаемая скорость.
		//В сырцах было именно 1000 и я
		//не стал менять это значение
		mVelocityTracker.computeCurrentVelocity(1000);

		//Получаем скорость текущую
		int vx = (int) mVelocityTracker.getXVelocity();
		int vy = (int) mVelocityTracker.getYVelocity();

		//Перед этим кодом был следующий коммент:
		//Сделаем это более похожим на карты.
		//Там скорость обрезается в два раза.
		vx = vx * 3 / 4;
		vy = vy * 3 / 4;

		//Специальный метод для скролла, когда мы отпустили палец
		mScroller.fling(dx, dy, vx, vy, 0, 1500, 0, 1500);

		//Уничтожаем наш VelocityTracker
		mVelocityTracker.recycle();

		return true;
	}

	}
	return true;
}

Думаю, что из исходника все ясно)
Теперь нам необходимо посчитать скролл и выводить что-то на экран. в моем случае - это просто картинка:

@Override
protected void onDraw(Canvas canvas) {
	//Считаем скролл
	mScroller.computeScrollOffset();

	//Получаем координаты
	dx = mScroller.getCurrX();
	dy = mScroller.getCurrY();

	//Выводим картинку
	canvas.drawBitmap(bmp, dx, dy, new Paint());

	//Повторяем цикл
	invalidate();
}

В результате получили почти полноценный скролл:

18 Март 2009

DroidGear roms

You could find this on CoolRom.com.

Now DroidGear supprots only Sega Game Gear and Sega Master System roms.

17 Март 2009

Забавный SoundPool…

В общем сегодня я решил немного заняться звуком в своем старкрафте и начал писать код с использованием SoundPool.
Что же мне удалось определить:

  • На форуме anddev.org прочитал, что нормально работает только с Wav 16-бит и с OGG… Так и вышло.
  • Неудобно при использовании большого числа звуков ( у меня их 1144 шутки), поскольку он подгружает все звуки в память… что делать теперь не знаю…
В общем ситуация оочень странная - нету официального API, как следствие нету нормальной документации… очень странный ход со стороны гугла, ведь игры очень прибыльная вещь…

13 Март 2009

JNI для андроида


Необходимые материалы

Для лучшего понимания рекомендую прочитать мой предыдущий пост про Hello World на Си для анроода.

Если вы используете не линукс, то вам нужна папка include из линуксового JDK, поскольку из-за незначительных различий виндовая не подходит(

Описание нативного метода в java-классе и получение хидера для Си

Нативный код в Java описывается с помощью ключевого слова native. В своем коде я заведу такую функцию:

public static native int hello(int val1, String val2);

Теперь необходимо собрать проект(я не нашел в эклипсе кнопки “Build”, поэтому я просто запускал проект), а затем перейти в папку /bin и выполнить там комманду:

javah %ClassName%

где %ClassName% - полное название класса, в котором мы написали этот метод. В моем случае - это hotheart.JNITest.JNITestActivity в результате мы получили заголовочный файл

 

К сожалению, мы не сможем воспользоваться вторым параметром и в нативном коде мы не сможем ничего о нем узнать. Поскольку в заголовочных файлах не описаны методы для работы с объектами. В частности String перейдет в jstring, который на самом деле jobject, который является просто пустой структурой. Но, возможно, это дело может исправить использование заголовочных файлов из самого андроида.

Изучение заголовочного файла и реализация метода

Теперь взглянем на сгенерированный заголовочный файл. Вот что получилось в моем случае:
(файл myjni.h)

/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class hotheart_JNITest_JNITestActivity */

#ifndef _Included_hotheart_JNITest_JNITestActivity
#define _Included_hotheart_JNITest_JNITestActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     hotheart_JNITest_JNITestActivity
 * Method:    hello
 * Signature: (ILjava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_hotheart_JNITest_JNITestActivity_hello
 (JNIEnv *, jclass, jint, jstring);

#ifdef __cplusplus
}
#endif
#endif

Рассмотрим комментарий перед описанием метода. Мы должны запомнить что здесь написано - мы будем это использовать в последствии.
В поле Class мы получили название метода, в Metod - название метода, Signature - Описание параметров и выходных значений метода.

Теперь реализуем этот метод. Я в своей реализации буду просто возвращать первый аргумент:
(файл myjni.c)

#include
#include "myjni.h"

#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jint JNICALL Java_hotheart_JNITest_JNITestActivity_hello
 (JNIEnv *a, jclass b, jint c, jstring d)
{
 return c;
}

#ifdef __cplusplus
}
#endif

Но! этого не достаточно для функционирования JNI. Необходимо при инициализации JNI регистрировать методы в джава-машине.

Делается это так:

static JNINativeMethod sMethods[] = {
 /* name, signature, funcPtr */

 {"hello", "(ILjava/lang/String;)I", (void*)Java_hotheart_JNITest_JNITestActivity_hello},
};

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
 JNIEnv* env = NULL;
 jint result = -1;

 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
 return result;
 }

 jniRegisterNativeMethods(env, "hotheart/JNITest/JNITestActivity", sMethods, 1);
 return JNI_VERSION_1_4;
}

Этот код приписываем в конец файла myjni.c
Массив sMethods представляет из себя список всех регистрируемых функций, а в методе JNI_OnLoad мы регистрируем сами функции.

 

Компиляция и загрузка библиотеки

Что бы теперь скомпилировать наш проект нужно немного видоизменить код для компиляции в случае с HelloWorld’ом - при компиляции нужно добавить параметры -i с путями к заголовкам (не забываем про пробелы), которые вы скачали, когда начали читать статью, а при линковке добавить ключ -shared.

В результате в моем случае получаем:

arm-none-linux-gnueabi-gcc -ID:\Android\AndroidJNI\jdk_include\ -ID:\Android\AndroidJNI\jdk_include\linux -fpic -c myjni.c -o D:\CompileTemp\myjni.o
arm-none-linux-gnueabi-ld -TD:\GCC\arm-none-linux-gnueabi\lib\ldscripts\armelf_linux_eabi.xsc -shared -o D:\CompileTemp\myjni.so D:\CompileTemp\myjni.o

Теперь с нативным кодом покончено и мы можем загрузить библиотеку в андроид.
Я положил в папку /data/data/hotheart.JNITest/, поскольку в эту папку мое приложение имеет гарантированный полный доступ. Теперь остался последний штрих - добавление кода для загрузки библиотеки в память:

System.load("/data/data/hotheart.JNITest/myjni.so");

В итоге мой java-код стал таким:

package hotheart.JNITest;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class JNITestActivity extends Activity {
 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main);
 TextView tv =  (TextView)findViewById(R.layout.hello);
 System.load("/data/data/hotheart.JNITest/myjni.so");
 tv.setText("Result =" + hello(10, "test"));
 }

 public static native int hello(int val1, String val2);
}

Все! теперь мы можем запустить наше приложение:

Hello World на Си для андроида

Что требуется для компиляции

  • Компилятор GCC для ARM. Далее буду описывать работу под виндами
  • Модифицированный скрипт, необходимый для адаптации компилятора для компилирования под андроид - armelf_linux_eabi.xsc

Отмазка

Я плохо разбираюсь в GCC и многого не понимаю еще и этот мануал - выдержка из слежующих блогов:

Компиляция HelloWorld’а со статичной линковкой

После установки компилятора мы можем сразу скомпилировать свой HelloWorld с таким кодом файла main.c:
#include <stdio.h>;
int main()
{
printf("Hello Kitty!");
    return 0;
}
Выполнив такой код в папке с этим файлом:
arm-none-linux-gnueabi-gcc -static main.c -o main
В результате мы получили бинарник теперь его необходимо загрузить на G1 или эмулятор, прописать права на выполнение и запустить:
adb push  main /data/myjni
adb shell
#cd /data
#chmod 777 myjni
#./myjni
В результате получим надпись “Hello Kitty!” на экране) Если не верите, то вот пруф - скриншот с экрана G1, но у меня myjni немного не тот бинарник. Результат подобных действий у меня в native:
Но есть огромный минус - статическая линковка. и таким образом мы подходим к следующему пункту.

Динамическая компиляция

В андроиде таблица импортов/экспортов немного не такая как сделана в этом компиляторе и поэтому необходимо вмешиваться в работу компилятора.
Первое, что нам нужно сделать - это скачать файл armelf_linux_eabi.xsc и заменить им такой же файл в дистрибе компилятора - %CompilerPath%\arm-none-linux-gnueabi\lib\ldscripts\
Затем нам нужно сделать так, что бы в пути к компилятору не было пробелов. Это необходимо, поскольку как-то некорректно работает этот GCC с парамертрами, которые содержат пробелы(
Я решил дело просто - сделал символьную ссылку на папку компилятора и назвал её D:\GCC
Теперь непосредственно компилируем и линкуем:
arm-none-linux-gnueabi-gcc -fpic -c myjni.c -o D:\CompileTemp\myjni.o
arm-none-linux-gnueabi-ld -TD:\GCC\arm-none-linux-gnueabi\lib\ldscripts\armelf_linux_eabi.xsc -shared -o D:\CompileTemp\myjni.so D:\CompileTemp\myjni.o 
Тут еще проблема была - выходной файл из компилятора без указания абсолютного пути писался непонятно куда… пришлось вручную писать во временную папку(
Теперь все с динамическим кодом и в результате мы получили полноценный HelloWorld

8 Март 2009

Ура! Удалось загрузить изображение карты!

Сегодня я смог добится загрузки карты старкрафта! Это еще один шажок на пути к реализации идеи)

Все идет пока что даже слишком легко… надеюсь у меня не будет проблем с AI. Насколько мне известно там простые скрипты, которые описывают каждое действие и не будет проблем и с этим)

разработка идет полным ходом, надеюсь, что в скором времени у меня уже будет пре-пре-пре-альфа версия и доведу я её до адекватного состояния и затем выложу на гуглокод.

На всякий случай вот пруфлинк(в мой блог не захотело аплоадится):

6 Март 2009

Эмулятор DroidGear теперь выложен на Code.Google

Ну вот теперь я решил выложить свои нынешние наработки на Code.Google) Начну с DroidGear!

Страница приложения на Google Code.

Небольшое описание.

DroidGear - это порт единственного(насколько мне известно) открытого Java-эмулятора Sega - JavaGear.

Основные возсожности/особенности и тпх:

  • Тормозной( дело в том, что либо я что-то не понимаю в андроиде, либо андроид еще слишком сырой и следует немного подождать до его оптимизаций. Но насколько мне извесно Java-машина Андроида вообще не предназначалась к таким ресурсоемким приложениям. Выход тут есть - написать нативный код на C++, чем я и планирую заняться через годик(а может и раньше) после окончания разработки Старкрафта
  • Поддержка Sega Master System, Sega Game Gear
  • Загрузка ROM’ов с карты памяти
  • Управление с клавиатуры… не представляю как без мультитача играть получится в приципе(

Несколько скриншотов:

16 Февраль 2009

Формат графический файлов GRP

Здесь я сначала размещу копипаст с какого-то английского ресурса, а затем сделаю перевод.

Делаю что бы не потерялось в сети это чудо)

UPD Нашел неточности, узнал значение неизвестных байтов
» Читать полностью …

3 Февраль 2009

Начата разработка игры StarCraft для Андроида

Сегодня с утра я проснулся от того, что мне позвонил друг… позвонил рано) даже очень) Но день, тем не менее не испортился. Поскольку у меня было много времени (появилось часа три-четыре) я вспомнил про мою любимую игру детства - StarCraft. Ну и соответственно, вспомнив как там все было сделано, я пришел к выводу, что это все вполне реализуемо.

И так. сейчас опишу то, чего я добился в эти три-четыре часа.

  • Загрузка одного юнита, в принципе можно и других, но пока нужно формализовать движок
  • Некоторая анимация - выравнивание изображения юнита по направлению движения
  • Найдены соответствующие утилиты для распаковки архивов и т.д.

Если учесть, что это все я получил часа за три, то думаю, что это не плохой результат для начала и все раельно реализуемо. Единственная проблема - это очень большое множество разных юнитов, у которых разная анимация, у некоторых состоит из двух файлов, у кого-то разная анимация при движении и неподвижности, у кого-то разная и тпх. Реализовывать придется все в коде в виде виртуальных классов. Вторая проблема - написание AI. Однако, когда он уже будет необходим, то я уж смогу показать многим людям, что я сделал, и, надеюсь, найдется хотя бы один человек, что бы его завершитЬ, поскольку тут всего и так много….