среда, 2 мая 2012 г.

11. Рекорды

В предыдущей статье, мы добавили вывод подсказки с финальной позицией при запуске новой игры. Сегодня мы добавим список рекордов, а также допишем недостающий код, управляющий жизненным циклом приложения, завершив, тем самым, разработку текущей итерации приложения.

11. Рекорды

Для отображения таблицы, удобнее всего использовать TableLayout. Создадим activity для вывода таблицы рекордов, для чего внесем изменения в  AndroidManifest.xml:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.whiterabbit.tags"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk android:minSdkVersion="7" />
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <provider android:name="PuzzleProvider"
            android:authorities="com.WhiteRabbit.provider.Puzzle">
        </provider>
        <activity
            android:name=".PuzzleActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".RecordActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:mimeType="vnd.android.cursor.dir/vnd.com.WhiteRabbit.Puzzle.sessions"/>
            </intent-filter>
        </activity>
        </application>
</manifest>


добавим в res/layout описание разметки (records.xml):

<?xml version="1.0" encoding="utf-8"?>
<TableLayout android:id="@+id/vw"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:stretchColumns="1">
    <TableRow>
        <TextView
            android:id="@+id/puzzle_name"
            android:layout_column="1"
            android:text="@string/puzzle_name_column"
            android:padding="3dip" />
        <TextView
            android:id="@+id/date"
            android:text="@string/date_column"
            android:gravity="left"
            android:padding="3dip" />
        <TextView
            android:id="@+id/step_cnt"
            android:text="@string/score_column"
            android:gravity="right"
            android:padding="3dip" />
        </TableRow>
    <View
        android:layout_height="2dip"
        android:background="#FF909090" />
</TableLayout>


и создадим класс, реализующий новую activity:

package com.whiterabbit.tags;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import android.app.Activity;
import android.content.ContentUris;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.Bundle;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;

public class RecordActivity extends Activity {
   
    private static final long PUZZLE_COLUMN_NAME = 21;
    private static final long DATE_COLUMN_NAME = 22;
    private static final long SCORE_COLUMN_NAME = 23;
   
    private static final int MAX_RECORDS_IN_GROUP = 5;
   
    TableLayout layout;
    private int currentLocale;
    private Map<TextView, Long> controls = new HashMap<TextView, Long>();
   
    private static final String[] STRINGS_PROJECTION =
            new String[] {
                PuzzleDb.StringValues._ID,
                PuzzleDb.StringValues.COLUMN_NAME_VALUE
        };

    private static final String[] SESSION_PROJECTION =
            new String[] {
                PuzzleDb.Sessions._ID,
                PuzzleDb.Puzzles.ALIAS_NAME_PUZZLE_NAME,
                PuzzleDb.Sessions.COLUMN_NAME_END_DATE,
                PuzzleDb.Stats.COLUMN_NAME_VALUE
        };
   
    public String getLocalizedString(long id) {
        String r = null;
        Uri uri = ContentUris.withAppendedId(PuzzleDb.Strings.CONTENT_URI, id);
        Cursor cursor = managedQuery(
                uri,
                STRINGS_PROJECTION,
                PuzzleDb.StringValues.COLUMN_NAME_LOCALE_ID + " = ?",     
                new String [] {Integer.toString(currentLocale)},
                null
            );
        if (cursor.moveToFirst()) {
            int stringsValueColumn = cursor.getColumnIndex(PuzzleDb.StringValues.COLUMN_NAME_VALUE);
            r = cursor.getString(stringsValueColumn);
        }
        return r;
    }
   
    private void addText(TableRow r, String s, boolean isChecked, boolean isRight, Long sessionId) {
        TextView c = new TextView(this);
        c.setText(s);
        if (isChecked) {
            c.setTypeface(null, Typeface.BOLD);
            c.setTextColor(Color.WHITE);
        }
        if (isRight) {
            c.setGravity(Gravity.RIGHT);
        }
        controls.put(c, sessionId);
        c.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    Long sessionId = controls.get(v);
                    if (sessionId != null) {
                        Uri uri = ContentUris.withAppendedId(PuzzleDb.Sessions.CONTENT_URI, sessionId);
                        setResult(RESULT_OK, new Intent().setData(uri));
                        finish();
                        return true;
                    }
                }
                return false;
            }
        });
        r.addView(c);
    }
   
    private void addRow(String name, String date, String score, boolean isChecked, Long sessionId) {
        TableRow r = new TableRow(this);
        addText(r, "  ",  isChecked, false, sessionId);
        addText(r, name,  isChecked, false, sessionId);
        addText(r, date,  isChecked, false, sessionId);
        addText(r, score, isChecked, true,  sessionId);
        layout.addView(r);
    }

    private void addRow(String name, String date, int score, boolean isChecked, Long sessionId) {
        addRow(name, date, Integer.toString(score), isChecked, sessionId);
    }
   
    private void addSeparator() {
        TableRow r = new TableRow(this);
        layout.addView(r);
    }
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.records);
        layout = (TableLayout)findViewById(R.id.vw);
       
        Bundle b = getIntent().getExtras();
        currentLocale = b.getInt(PuzzleDb.StringValues.COLUMN_NAME_LOCALE_ID);
        TextView c = (TextView)findViewById(R.id.puzzle_name);
        if (c != null) {
            c.setText(getLocalizedString(PUZZLE_COLUMN_NAME));
        }
        c = (TextView)findViewById(R.id.date);
        if (c != null) {
            c.setText(getLocalizedString(DATE_COLUMN_NAME));
        }
        c = (TextView)findViewById(R.id.step_cnt);
        if (c != null) {
            c.setText(getLocalizedString(SCORE_COLUMN_NAME));
        }
       
        Uri uri = PuzzleDb.Sessions.CONTENT_URI;
        Cursor cursor = managedQuery(
                uri,
                SESSION_PROJECTION,
                PuzzleDb.Sessions.COLUMN_NAME_IS_CLOSED + " = 1 and not " + PuzzleDb.Sessions.COLUMN_NAME_END_DATE + " is null",     
                new String [] {Integer.toString(currentLocale)},
                null
            );
        Set<Long> oldSessions = new HashSet<Long>();
        String prev = null;
        int recordsCnt = 0;
        for (cursor.moveToFirst();!cursor.isAfterLast();cursor.moveToNext()) {
            int sessionIdColumn = cursor.getColumnIndex(PuzzleDb.Sessions._ID);
            int puzzleNameColumn = cursor.getColumnIndex(PuzzleDb.Puzzles.ALIAS_NAME_PUZZLE_NAME);
            int endDateColumn = cursor.getColumnIndex(PuzzleDb.Sessions.COLUMN_NAME_END_DATE);
            int scoreColumn = cursor.getColumnIndex(PuzzleDb.Stats.COLUMN_NAME_VALUE);
            Long sessionId = cursor.getLong(sessionIdColumn);
            String puzzleName = cursor.getString(puzzleNameColumn);
            String endDate = cursor.getString(endDateColumn);
            int score = cursor.getInt(scoreColumn);
            boolean isChecked = false;
            if (b.getLong(PuzzleDb.Sessions.ALIAS_NAME_SESSION_ID) == sessionId) {
                isChecked = true;
            }
            if ((prev != null)&& !prev.equals(puzzleName)) {
                addSeparator();
                recordsCnt = 0;
            }
            if ((isChecked ? recordsCnt : recordsCnt + 1) >= MAX_RECORDS_IN_GROUP) {
                oldSessions.add(sessionId);
            } else {
                addRow(puzzleName, endDate, score, isChecked, sessionId);
                recordsCnt++;
            }
            prev = puzzleName;
        }
        for (Long id: oldSessions) {
            uri = ContentUris.withAppendedId(PuzzleDb.Sessions.CONTENT_URI, id);
            getContentResolver().delete(uri, PuzzleDb.Sessions.COLUMN_NAME_IS_CLOSED + " = 1", null);
        }
    }
}


Здесь мы получаем параметры из передаваемого нам намерения (currentLocale) и заполняем TableLayout списком закрытых сессий. Внесем необходимые дополнения в PuzzleActivity:

package com.whiterabbit.tags;

...
public class PuzzleActivity extends Activity {

    ...
    private static final int RECORDS_REQUEST = 1;

    private int currentLocale = PuzzleDb.Locales.LOCALE_EN;
    private int currentPuzzle;
    private long currentPosition;
    private long currentProfile;
    private long sessionId = -1;
    private boolean isSessionCreated = false;

    ...
    private static final String[] SESSION_PROJECTION =
            new String[] {
                PuzzleDb.Sessions._ID,
                PuzzleDb.Sessions.COLUMN_NAME_PROFILE_ID,
                PuzzleDb.Sessions.COLUMN_NAME_PUZZLE_ID,
                PuzzleDb.Sessions.COLUMN_NAME_POSITION_ID,
                PuzzleDb.Sessions.COLUMN_NAME_IS_CLOSED,
                PuzzleDb.Profiles.COLUMN_NAME_LOCALE_ID
        };
   
    private static final String[] STAT_PROJECTION =
            new String[] {
                PuzzleDb.Stats._ID,
                PuzzleDb.Stats.COLUMN_NAME_STAT_TYPE_ID,
                PuzzleDb.Stats.COLUMN_NAME_VALUE
        };

    ...
    public void loadStat() {
        view.setCurrStep(0);
        Uri uri = ContentUris.withAppendedId(PuzzleDb.Stats.CONTENT_URI, PuzzleDb.StatTypes.Steps);
        Cursor cursor = managedQuery(
                uri,
                STAT_PROJECTION,
                PuzzleDb.Stats.COLUMN_NAME_SESSION_ID + " = ?",     
                new String [] {Long.toString(sessionId)},
                null
            );
        if (cursor.moveToFirst()) {
            int valueColumn = cursor.getColumnIndex(PuzzleDb.Stats.COLUMN_NAME_VALUE);
            long currStep = cursor.getLong(valueColumn);
            view.setCurrStep(currStep);
        }
    }
   
    public void addStat() {
        if (sessionId < 0) return;
        Uri uri = PuzzleDb.Stats.CONTENT_URI;
        ContentValues values = new ContentValues();
        values.put(PuzzleDb.Stats.COLUMN_NAME_STAT_TYPE_ID, PuzzleDb.StatTypes.Steps);
        values.put(PuzzleDb.Stats.COLUMN_NAME_SESSION_ID, sessionId);
        values.put(PuzzleDb.Stats.COLUMN_NAME_VALUE, view.getCurrStep());
        getContentResolver().insert(uri, values);
    }

    public void saveStat() {
        if (sessionId < 0) return;
        Uri uri = ContentUris.withAppendedId(PuzzleDb.Stats.CONTENT_URI, PuzzleDb.StatTypes.Steps);
        ContentValues values = new ContentValues();
        values.put(PuzzleDb.Stats.COLUMN_NAME_VALUE, view.getCurrStep());
        if (getContentResolver().update(uri, values, PuzzleDb.Stats.COLUMN_NAME_SESSION_ID + " = " + Long.toString(sessionId), null) == 0) {
            addStat();
        }
    }
   
    private boolean loadSession() {
        Uri uri = PuzzleDb.Sessions.CONTENT_URI;
        Cursor cursor = managedQuery(
                uri,
                SESSION_PROJECTION,
                PuzzleDb.Sessions.COLUMN_NAME_IS_CLOSED + " = 0 ",     
                new String [] {Integer.toString(currentLocale)},
                null
            );
        if (cursor.moveToFirst()) {
            int idColumn = cursor.getColumnIndex(PuzzleDb.Sessions._ID);
            int profileIdColumn = cursor.getColumnIndex(PuzzleDb.Sessions.COLUMN_NAME_PROFILE_ID);
            int puzzleIdColumn = cursor.getColumnIndex(PuzzleDb.Sessions.COLUMN_NAME_PUZZLE_ID);
            int positionIdColumn = cursor.getColumnIndex(PuzzleDb.Sessions.COLUMN_NAME_POSITION_ID);
            int localeIdColumn = cursor.getColumnIndex(PuzzleDb.Profiles.COLUMN_NAME_LOCALE_ID);
            sessionId = cursor.getInt(idColumn);
            currentProfile = cursor.getInt(profileIdColumn);
            currentPuzzle = cursor.getInt(puzzleIdColumn);
            currentPosition = cursor.getInt(positionIdColumn);
            currentLocale = cursor.getInt(localeIdColumn);
            isSessionCreated = true;
            return true;
        }
        return false;
    }

    public void putTag(long positionId, long tagId, int x, int y) {
        ContentValues values = new ContentValues();
        values.put(PuzzleDb.TagPositions.COLUMN_NAME_POSITION_ID, positionId);
        values.put(PuzzleDb.TagPositions.COLUMN_NAME_TAG_ID, tagId);
        values.put(PuzzleDb.TagPositions.COLUMN_NAME_X, x);
        values.put(PuzzleDb.TagPositions.COLUMN_NAME_Y, y);
        getContentResolver().insert(PuzzleDb.TagPositions.CONTENT_URI, values);
    }
   
    public void createPosition() {
        ContentValues values = new ContentValues();
        Uri uri = getContentResolver().insert(PuzzleDb.Positions.CONTENT_URI, values);
        if (uri != null) {
            currentPosition = Long.parseLong(uri.getPathSegments().get(1));
        } else {
            currentPosition = -1;
        }
    }
   
    public void createSession() {
        if (currentPosition < 0) return;
        Date now = new Date();
        SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");       
        ContentValues values = new ContentValues();
        values.put(PuzzleDb.Sessions.COLUMN_NAME_PROFILE_ID, currentProfile);
        values.put(PuzzleDb.Sessions.COLUMN_NAME_PUZZLE_ID, currentPuzzle);
        values.put(PuzzleDb.Sessions.COLUMN_NAME_POSITION_ID, currentPosition);
        values.put(PuzzleDb.Sessions.COLUMN_NAME_IS_CLOSED, 0);
        values.put(PuzzleDb.Sessions.COLUMN_NAME_IS_CURRENT, 1);
        values.put(PuzzleDb.Sessions.COLUMN_NAME_START_DATE, formatter.format(now));
        Uri uri = getContentResolver().insert(PuzzleDb.Sessions.CONTENT_URI, values);
        if (uri != null) {
            sessionId = Long.parseLong(uri.getPathSegments().get(1));
        } else {
            sessionId = -1;
        }
    }
   
    public void saveSession() {
        Uri uri = ContentUris.withAppendedId(PuzzleDb.Sessions.CONTENT_URI, sessionId);
        ContentValues values = new ContentValues();
        values.put(PuzzleDb.Sessions.COLUMN_NAME_POSITION_ID, currentPosition);
        getContentResolver().update(uri, values, null, null);
    }
   
    private void closeSession() {
        Date now = new Date();
        SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");       
        Uri uri = ContentUris.withAppendedId(PuzzleDb.Sessions.CONTENT_URI, sessionId);
        ContentValues values = new ContentValues();
        values.put(PuzzleDb.Sessions.COLUMN_NAME_IS_CLOSED, 1);
        values.put(PuzzleDb.Sessions.COLUMN_NAME_END_DATE, formatter.format(now));
        getContentResolver().update(uri, values, null, null);
    }

    public void deleteSession() {
        if (!isSessionCreated) return;
        if (sessionId < 0) return;
        Uri uri = ContentUris.withAppendedId(PuzzleDb.Sessions.CONTENT_URI, sessionId);
        getContentResolver().delete(uri, PuzzleDb.Sessions.COLUMN_NAME_IS_CLOSED + " = 0", null);
        isSessionCreated = false;
        sessionId = -1;
    }

    public void deletePosition(long positionId) {
        Uri uri = ContentUris.withAppendedId(PuzzleDb.Positions.CONTENT_URI, positionId);
        getContentResolver().delete(uri, null, null);
    }

    private void savePosition() {
        if (isSessionCreated) {
            long oldPositionId = currentPosition;
            createPosition();
            if (currentPosition > 0) {
                view.savePosition(currentPosition);
            }
            saveSession();
            if (oldPositionId > 0) {
                deletePosition(oldPositionId);
            }
            saveStat();
        } else {
               createPosition();
               createSession();
               if (currentPosition > 0) {
                   view.savePosition(currentPosition);
               }
            addStat();
               isSessionCreated = true;
        }
    }
   
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case RECORDS_REQUEST:
                loadProfile();
                createSession();
                view.loadPuzzle(currentPuzzle, currentPosition);
                view.setCurrStep(0);
                break;
        }
    }

    public void onSucceed() {
        view.invalidate();
        savePosition();
        closeSession();
        Intent records = new Intent(Intent.ACTION_VIEW);
        records.setData(PuzzleDb.Sessions.CONTENT_URI);
        records.putExtra(PuzzleDb.Sessions.ALIAS_NAME_SESSION_ID, sessionId);
        records.putExtra(PuzzleDb.StringValues.COLUMN_NAME_LOCALE_ID, currentLocale);
        startActivityForResult(records, RECORDS_REQUEST);
    }
   
    protected void onPause() {
        savePosition();
        super.onPause();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        LinearLayout.LayoutParams containerParams =
                new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT, 0.0F);
        LinearLayout root = new LinearLayout(this);
        root.setOrientation(LinearLayout.VERTICAL);
        root.setBackgroundColor(Color.LTGRAY);
        root.setLayoutParams(containerParams);
        view = new MainView(this, this);
        if (loadSession()) {
            loadStat();
        } else {
            loadProfile();
        }
        view.loadPuzzle(currentPuzzle, currentPosition);
        root.addView(view);
        setContentView(root);
   }
}


Здесь мы добавили метод onSucceed который вызывается MainView при обнаружении финальной позиции, в котором мы формируем намерение (Invent), передаем ему необходимые данные (currentLocale, sessionId) и вызываем activity методом startActivityForResult (позволяющим вернуть данные из вызванной активности, если нам это понадобиться). 
Данные из вызванной активности принимаются методом onActivityResult, на текущей итерации, мы не анализируем возвращаемые нам данные, а просто загружаем стартовую позицию текущей головоломки, начиная игру сначала. Внесем необходимые изменения в MainView:

package com.whiterabbit.tags;

...
public class MainView extends View {

    ...
    private PuzzleActivity callback;
    private Long currStep = 0L;

    public MainView(Context context, PuzzleActivity callback) {
        super(context);
        this.callback = callback;
        ...
    }
       
    public void savePosition(long positionId) {
        model.savePosition(positionId);
    }
   
    public void setCurrStep(long currStep) {
        this.currStep = currStep;
    }
   
    public long getCurrStep() {
        return currStep;
    }
    ...
}


и Model:

package com.whiterabbit.tags;
...
public class Model {
    ...
    private boolean checkEndPosition(Map<Long, Tag> pos) {
        boolean r = false;
        for (Tag tag: pos.values()) {
            for (Tag t: tags.values()) {
                if (tag.getId() == t.getId()) {
                    if (tag.getX() != t.getX()) return false;
                    if (tag.getY() != t.getY()) return false;
                    r = true;
                }
            }
        }
        return r;
    }
   
    public boolean checkEndPositions() {
        for (Map<Long, Tag> pos: endpositions) {
            if (checkEndPosition(pos)) {
                return true;
            }
        }
        return false;
    }
    ...
}


В PuzzleProvider добавим обработку добавленных нами запросов:

package com.whiterabbit.tags;

...
public class PuzzleProvider extends ContentProvider {

   ...
   private static final int STRING_URI_INDICATOR        = 1;
   private static final int LOCALE_URI_INDICATOR        = 2;
   private static final int PROFILE_URI_INDICATOR       = 3;
   private static final int PUZZLE_LIST_URI_INDICATOR   = 4;
   private static final int ENDPOS_ITEM_URI_INDICATOR   = 5;
   private static final int PARAMS_URI_INDICATOR        = 6;
   private static final int POSITION_ITEM_URI_INDICATOR = 7;
   private static final int SESSION_URI_INDICATOR       = 8;
   private static final int SESSION_ITEM_URI_INDICATOR  = 9;
   private static final int POSITION_URI_INDICATOR      = 10;
   private static final int TAG_URI_INDICATOR           = 11;
   private static final int STAT_URI_INDICATOR          = 13;
   private static final int STAT_ITEM_URI_INDICATOR     = 14;

   static {
       uriMatcher.addURI(PuzzleDb.AUTHORITY, PuzzleDb.Strings.PATH_STRING + "/#", STRING_URI_INDICATOR);
       uriMatcher.addURI(PuzzleDb.AUTHORITY, PuzzleDb.Locales.PATH_LOCALE, LOCALE_URI_INDICATOR);
       uriMatcher.addURI(PuzzleDb.AUTHORITY, PuzzleDb.Profiles.PATH_PROFILE, PROFILE_URI_INDICATOR);
       uriMatcher.addURI(PuzzleDb.AUTHORITY, PuzzleDb.Puzzles.PATH_PUZZLE, PUZZLE_LIST_URI_INDICATOR);
       uriMatcher.addURI(PuzzleDb.AUTHORITY, PuzzleDb.EndPositions.PATH_ENDS  + "/#", ENDPOS_ITEM_URI_INDICATOR);
       uriMatcher.addURI(PuzzleDb.AUTHORITY, PuzzleDb.Params.PATH_PARAMS + "/#", PARAMS_URI_INDICATOR);
       uriMatcher.addURI(PuzzleDb.AUTHORITY, PuzzleDb.Positions.PATH_POSITION + "/#", POSITION_ITEM_URI_INDICATOR);
       uriMatcher.addURI(PuzzleDb.AUTHORITY, PuzzleDb.Sessions.PATH_SESSION, SESSION_URI_INDICATOR);
       uriMatcher.addURI(PuzzleDb.AUTHORITY, PuzzleDb.Sessions.PATH_SESSION + "/#", SESSION_ITEM_URI_INDICATOR);
       uriMatcher.addURI(PuzzleDb.AUTHORITY, PuzzleDb.Positions.PATH_POSITION, POSITION_URI_INDICATOR);
       uriMatcher.addURI(PuzzleDb.AUTHORITY, PuzzleDb.TagPositions.PATH_TAG, TAG_URI_INDICATOR);
       uriMatcher.addURI(PuzzleDb.AUTHORITY, PuzzleDb.Stats.PATH_STAT, STAT_URI_INDICATOR);
       uriMatcher.addURI(PuzzleDb.AUTHORITY, PuzzleDb.Stats.PATH_STAT + "/#", STAT_ITEM_URI_INDICATOR);
   }

   @Override
   public String getType(Uri uri) {
       switch (uriMatcher.match(uri)) {
            case STRING_URI_INDICATOR:
                return PuzzleDb.Strings.CONTENT_ITEM_TYPE;
               case LOCALE_URI_INDICATOR:
                   return PuzzleDb.Locales.CONTENT_DIR_TYPE;
               case PROFILE_URI_INDICATOR:
                   return PuzzleDb.Profiles.CONTENT_DIR_TYPE;
               case PUZZLE_LIST_URI_INDICATOR:
                   return PuzzleDb.Puzzles.CONTENT_DIR_TYPE;
               case ENDPOS_ITEM_URI_INDICATOR:
                   return PuzzleDb.EndPositions.CONTENT_ITEM_TYPE;
            case PARAMS_URI_INDICATOR:
                return PuzzleDb.Params.CONTENT_ITEM_TYPE;
               case POSITION_ITEM_URI_INDICATOR:
                   return PuzzleDb.Positions.CONTENT_ITEM_TYPE;
               case SESSION_URI_INDICATOR:
                   return PuzzleDb.Sessions.CONTENT_DIR_TYPE;
               case SESSION_ITEM_URI_INDICATOR:
                   return PuzzleDb.Sessions.CONTENT_ITEM_TYPE;
               case POSITION_URI_INDICATOR:
                   return PuzzleDb.Positions.CONTENT_DIR_TYPE;
               case TAG_URI_INDICATOR:
                   return PuzzleDb.TagPositions.CONTENT_DIR_TYPE;
               case STAT_URI_INDICATOR:
                   return PuzzleDb.Stats.CONTENT_DIR_TYPE;
               case STAT_ITEM_URI_INDICATOR:
                   return PuzzleDb.Stats.CONTENT_ITEM_TYPE;
       }
       return null;
   }

   @Override
   public Uri insert(Uri uri, ContentValues values) {
       SQLiteDatabase db = mOpenHelper.getWritableDatabase();
       switch (uriMatcher.match(uri)) {
          case SESSION_URI_INDICATOR:
               db.execSQL("update " + PuzzleDb.Sessions.TABLE_NAME + " set " +
                       PuzzleDb.Sessions.COLUMN_NAME_IS_CLOSED + " = 1," +
                       PuzzleDb.Sessions.COLUMN_NAME_IS_CURRENT + " = 0");
               long sessionId = db.insert(PuzzleDb.Sessions.TABLE_NAME,
                       PuzzleDb.Sessions._ID,
                       values);
               if (sessionId > 0) {
                   return ContentUris.withAppendedId(PuzzleDb.Sessions.CONTENT_URI, sessionId);
               }
               break;
          case POSITION_URI_INDICATOR:
               values.put(PuzzleDb.Positions.COLUMN_NAME_IS_PROTECTED, 0);
               long positionId = db.insert(PuzzleDb.Positions.TABLE_NAME,
                       PuzzleDb.Positions._ID,
                       values);
               if (positionId > 0) {
                   return ContentUris.withAppendedId(PuzzleDb.Positions.CONTENT_URI, positionId);
               }
               break;
           case TAG_URI_INDICATOR:
               long tagId = db.insert(PuzzleDb.TagPositions.TABLE_NAME,
                       PuzzleDb.TagPositions._ID,
                       values);
               if (tagId > 0) {
                   return ContentUris.withAppendedId(PuzzleDb.TagPositions.CONTENT_URI, tagId);
               }
               break;
        case STAT_URI_INDICATOR:
               long statId = db.insert(PuzzleDb.Stats.TABLE_NAME,
                       PuzzleDb.Stats._ID,
                       values);
               if (statId > 0) {
                   return ContentUris.withAppendedId(PuzzleDb.Stats.CONTENT_URI, statId);
               }
            break;
       }
       return null;
   }

   @Override
   public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
       SQLiteDatabase db = mOpenHelper.getWritableDatabase();
       switch (uriMatcher.match(uri)) {
          case PROFILE_URI_INDICATOR:
               return db.update(PuzzleDb.Profiles.TABLE_NAME,
                       values,
                       PuzzleDb.Profiles.COLUMN_NAME_IS_DEFAULT + " = 1",
                       null);
           case SESSION_ITEM_URI_INDICATOR:
               return db.update(PuzzleDb.Sessions.TABLE_NAME,
                       values,
                       PuzzleDb.Sessions._ID + " = ?",
                       new String[] {uri.getPathSegments().get(1)});
           case STAT_ITEM_URI_INDICATOR:
               return db.update(PuzzleDb.Stats.TABLE_NAME,
                       values,
                       where + " and " + PuzzleDb.Stats.COLUMN_NAME_STAT_TYPE_ID + " = " + uri.getPathSegments().get(1),
                       whereArgs);
       }
       return 0;
   }
  
   @Override
   public int delete(Uri uri, String selection, String[] selectionArgs) {
       int r = 0;
       SQLiteDatabase db = mOpenHelper.getWritableDatabase();
       switch (uriMatcher.match(uri)) {
               case SESSION_ITEM_URI_INDICATOR:
                   r = db.delete(PuzzleDb.Sessions.TABLE_NAME,
                       selection + " and " +
                       PuzzleDb.Sessions._ID + " = ?",
                       new String[] {uri.getPathSegments().get(1)});
               break;
            case POSITION_ITEM_URI_INDICATOR:
                  r = db.delete(PuzzleDb.Positions.TABLE_NAME,
                         PuzzleDb.Positions._ID + " = ? and " +
                        PuzzleDb.Positions.COLUMN_NAME_IS_PROTECTED + " = 0",
                          new String[] {uri.getPathSegments().get(1)});
                  if (r > 0) {
                      db.delete(PuzzleDb.TagPositions.TABLE_NAME,
                              PuzzleDb.TagPositions.COLUMN_NAME_POSITION_ID + " = ?",
                              new String[] {uri.getPathSegments().get(1)});
                  }
                  return r;
       }
       return r;
   }

   @Override
   public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
       SQLiteDatabase db = mOpenHelper.getReadableDatabase();
       switch (uriMatcher.match(uri)) {
          case SESSION_URI_INDICATOR:
               return db.rawQuery("select a." + PuzzleDb.Sessions._ID + " as " + PuzzleDb.Sessions._ID + ", " +
                       "a." + PuzzleDb.Sessions.COLUMN_NAME_PROFILE_ID + " as " + PuzzleDb.Sessions.COLUMN_NAME_PROFILE_ID + ", " +
                       "a." + PuzzleDb.Sessions.COLUMN_NAME_PUZZLE_ID + " as " + PuzzleDb.Sessions.COLUMN_NAME_PUZZLE_ID + ", " +
                       "a." + PuzzleDb.Sessions.COLUMN_NAME_POSITION_ID + " as " + PuzzleDb.Sessions.COLUMN_NAME_POSITION_ID + ", " +
                       "b." + PuzzleDb.Profiles.COLUMN_NAME_LOCALE_ID + " as " + PuzzleDb.Profiles.COLUMN_NAME_LOCALE_ID + ", " +
                       "c." + PuzzleDb.Stats.COLUMN_NAME_VALUE + " as " + PuzzleDb.Stats.COLUMN_NAME_VALUE + ", " +
                       "e." + PuzzleDb.StringValues.COLUMN_NAME_VALUE + " as " + PuzzleDb.Puzzles.ALIAS_NAME_PUZZLE_NAME + ", " +
                       "a." + PuzzleDb.Sessions.COLUMN_NAME_END_DATE + " as " + PuzzleDb.Sessions.COLUMN_NAME_END_DATE + " " +
                       "from " + PuzzleDb.Sessions.TABLE_NAME + " a, " +
                       PuzzleDb.Profiles.TABLE_NAME + " b," +
                       PuzzleDb.Stats.TABLE_NAME + " c," +
                       PuzzleDb.Puzzles.TABLE_NAME + " d, " +
                       PuzzleDb.StringValues.TABLE_NAME + " e " +
                       "where b." + PuzzleDb.Sessions._ID + " = a." + PuzzleDb.Sessions.COLUMN_NAME_PROFILE_ID + " " +
                       "and c." + PuzzleDb.Stats.COLUMN_NAME_SESSION_ID + " = a." + PuzzleDb.Sessions._ID + " " +
                          "and c." + PuzzleDb.Stats.COLUMN_NAME_STAT_TYPE_ID + " = 1 " +
                       "and d." + PuzzleDb.Puzzles._ID + " = a." + PuzzleDb.Sessions.COLUMN_NAME_PUZZLE_ID + " " +
                          "and e." + PuzzleDb.StringValues.COLUMN_NAME_STRING_ID + " = d." + PuzzleDb.Puzzles.COLUMN_NAME_STRING_ID + " " +
                          "and e." + PuzzleDb.StringValues.COLUMN_NAME_LOCALE_ID + " = ? " +
                          "and " + selection + " order by " +
                          PuzzleDb.Sessions.COLUMN_NAME_PUZZLE_ID + " desc," +
                          PuzzleDb.Stats.COLUMN_NAME_VALUE, selectionArgs);
           case STAT_ITEM_URI_INDICATOR:
               return db.rawQuery("select " + PuzzleDb.Stats.COLUMN_NAME_VALUE + " " +
                                  "from " + PuzzleDb.Stats.TABLE_NAME + " " +
                                  "where " + selection +
                                  "and " + PuzzleDb.Stats.COLUMN_NAME_STAT_TYPE_ID + " = " + uri.getPathSegments().get(1), selectionArgs);
          case STRING_URI_INDICATOR:
               return db.rawQuery("select " + PuzzleDb.StringValues._ID +
                                      ", " + PuzzleDb.StringValues.COLUMN_NAME_VALUE +
                                      " from " + PuzzleDb.StringValues.TABLE_NAME +
                                      " where " + PuzzleDb.StringValues.COLUMN_NAME_STRING_ID +
                                      " = " + uri.getPathSegments().get(1) +
                                      " and " + selection, selectionArgs);
           case LOCALE_URI_INDICATOR:
               return db.rawQuery("select a." + PuzzleDb.Locales._ID + " as " + PuzzleDb.Locales._ID + ", " +
                                   "b." + PuzzleDb.StringValues.COLUMN_NAME_VALUE + " as " + PuzzleDb.StringValues.COLUMN_NAME_VALUE + " " +
                                   "from " + PuzzleDb.Locales.TABLE_NAME + " a, " +
                                   PuzzleDb.StringValues.TABLE_NAME + " b " +
                                   "where b." + PuzzleDb.StringValues.COLUMN_NAME_STRING_ID + " = " +
                                   "a." + PuzzleDb.Locales.COLUMN_NAME_STRING_ID + " and " + selection, selectionArgs);
           case PUZZLE_LIST_URI_INDICATOR:
               return db.rawQuery("select " +
                                  "a." + PuzzleDb.Puzzles._ID + " as " + PuzzleDb.Puzzles._ID + ", " +
                                      "b." + PuzzleDb.StringValues.COLUMN_NAME_VALUE + " as " + PuzzleDb.StringValues.COLUMN_NAME_VALUE + " from " +
                                   PuzzleDb.Puzzles.TABLE_NAME + " a, " +
                                   PuzzleDb.StringValues.TABLE_NAME + " b where " +
                                  "b." + PuzzleDb.StringValues.COLUMN_NAME_STRING_ID + " = " +
                                  "a." + PuzzleDb.Puzzles.COLUMN_NAME_STRING_ID + " and " +
                                  "b." + selection, selectionArgs);
           case PROFILE_URI_INDICATOR:
               return db.rawQuery("select a." + PuzzleDb.Profiles._ID + " as " + PuzzleDb.Profiles._ID + ", " +
                                   "a." + PuzzleDb.Profiles.COLUMN_NAME_LOCALE_ID + " as " + PuzzleDb.Profiles.COLUMN_NAME_LOCALE_ID + ", " +
                                   "a." + PuzzleDb.Profiles.COLUMN_NAME_PUZZLE_ID + " as " + PuzzleDb.Profiles.COLUMN_NAME_PUZZLE_ID + ", " +
                                   "b." + PuzzleDb.Puzzles.COLUMN_NAME_START_POSITION_ID + " as " + PuzzleDb.Puzzles.COLUMN_NAME_START_POSITION_ID + " " +
                                   "from " + PuzzleDb.Profiles.TABLE_NAME + " a, " +
                                   PuzzleDb.Puzzles.TABLE_NAME + " b " +
                                   "where a." + PuzzleDb.Profiles.COLUMN_NAME_IS_DEFAULT + " = 1 " +
                                   "and b." + PuzzleDb.Puzzles._ID + " = a." + PuzzleDb.Profiles.COLUMN_NAME_PUZZLE_ID, selectionArgs);
           case ENDPOS_ITEM_URI_INDICATOR:
               return db.rawQuery("select " + PuzzleDb.EndPositions.COLUMN_NAME_POSITION_ID + " " +
                                  "from " + PuzzleDb.EndPositions.TABLE_NAME + " " +
                                  "where " + PuzzleDb.EndPositions.COLUMN_NAME_PUZZLE_ID + " = " + uri.getPathSegments().get(1), selectionArgs);
           case PARAMS_URI_INDICATOR:
               return db.rawQuery("select " +
                                   PuzzleDb.Params._ID + ", " +
                                   PuzzleDb.Params.COLUMN_NAME_PARAM_TYPE_ID + ", " +
                                   PuzzleDb.Params.COLUMN_NAME_VALUE + " from " +
                                   PuzzleDb.Params.TABLE_NAME + " where " +
                                   PuzzleDb.Params.COLUMN_NAME_PUZZLE_ID + " = " +
                                   uri.getPathSegments().get(1), selectionArgs);
           case POSITION_ITEM_URI_INDICATOR:
               return db.rawQuery("select " +
                                   "b." + PuzzleDb.Tags.COLUMN_NAME_IX + " as " + PuzzleDb.Tags.COLUMN_NAME_IX + ", " +
                                   "d." + PuzzleDb.Items._ID + " as " + PuzzleDb.Items._ID + ", " +
                                   "b." + PuzzleDb.Tags._ID + "  as " + PuzzleDb.Items.COLUMN_NAME_TAG_ID + ", " +
                                   "c." + PuzzleDb.TagPositions.COLUMN_NAME_X + " + d." + PuzzleDb.Items.COLUMN_NAME_X + " as " + PuzzleDb.Items.COLUMN_NAME_X + ", " +
                                   "c." + PuzzleDb.TagPositions.COLUMN_NAME_Y + " + d." + PuzzleDb.Items.COLUMN_NAME_Y + " as " + PuzzleDb.Items.COLUMN_NAME_Y + ", " +
                                   "d." + PuzzleDb.Items.COLUMN_NAME_IMG_ID + " as " + PuzzleDb.Items.COLUMN_NAME_IMG_ID + ", " +
                                   "d." + PuzzleDb.Items.COLUMN_NAME_X + " as " + PuzzleDb.Items.COLUMN_NAME_ITEM_X + ", " +
                                   "d." + PuzzleDb.Items.COLUMN_NAME_Y + " as " + PuzzleDb.Items.COLUMN_NAME_ITEM_Y + " " +
                                   "from   " + PuzzleDb.Tags.TABLE_NAME + " b, " + PuzzleDb.TagPositions.TABLE_NAME + " c, " + PuzzleDb.Items.TABLE_NAME + " d " +
                                   "where  c." + PuzzleDb.TagPositions.COLUMN_NAME_TAG_ID + " = b." + PuzzleDb.Tags._ID + " " +
                                   "and    d." + PuzzleDb.Items.COLUMN_NAME_TAG_ID + " = b." + PuzzleDb.Tags._ID + " " +
                                   "and " + selection + " " +
                                   "and    c." + PuzzleDb.TagPositions.COLUMN_NAME_POSITION_ID + " = " +
                                   uri.getPathSegments().get(1), selectionArgs);
       }
       return null;
   }
   ...
}


Для того чтобы протестировать наши изменения (не решая головоломку), временно изменим описание финальной позиции в БД и пересоздадим базу (для этого достаточно удалить файл /data/data/com.whiterabbit.tags/databases/puzzle.db на эмуляторе, воспользовавшись вкладкой File Explorer перспективы DDMS):

package com.whiterabbit.tags;
...
public class PuzzleProvider extends ContentProvider {
       ...
       @Override
       public void onCreate(SQLiteDatabase db) {
           ...
           addTagPos(db, "1,  1,  1, 1, 1");
           addTagPos(db, "2,  2,  1, 2, 1");
           addTagPos(db, "3,  3,  1, 4, 1");
           addTagPos(db, "4,  4,  1, 1, 3");
           addTagPos(db, "5,  5,  1, 2, 3");
           addTagPos(db, "6,  6,  1, 4, 3");
           addTagPos(db, "7,  7,  1, 2, 4");
           addTagPos(db, "8,  8,  1, 3, 4");
           addTagPos(db, "9,  9,  1, 1, 5");
           addTagPos(db, "10, 10, 1, 4, 5");
//         addTagPos(db, "11, 2,  2, 2, 4");
          
           // DEBUG:
           addTagPos(db, "11, 2,  2, 2, 2");
          
           patch_2(db);
       }
       ...
}


Передвинув фишки в новую финальную позицию, как и ожидалось, видим добавленную нами таблицу рекордов:






На этом цикл статей, посвященных разработке пятнашек закончен. Исходники проекта под Eclipse можно забрать здесь.


Комментариев нет:

Отправить комментарий